为什么需要模块化?
当我们在html中调用一个js函数时,如果我们把这个函数写在另外的一个js文件中,那么调用的时候我们需要在html的头部引入那个js文件。
index.html
Hello world
index.js
function Girl(){ var p = document.getElementById("boy"); p.innerHTML = "I am a boy";}
此时,若我们需要在index.js中生成的文字是动态的,且由另一个js(matn.js)产生,那么如果在java中可以在index.js中使用import package+class模式引用另一个文件中的方法,但是对于javascript这种动态的语言来说是不可以的。因此如果我们要在index.js中能够调用math.js中的函数,那么我们需要同时在index.html中引入math.js。
index.html
Hello world
index.js
//import "math.js" 不支持这种写法function Girl(){ var p = document.getElementById("boy"); p.innerHTML = add(1,2);}
math.js
function add(a,b){ return a + b;}
我们可以看到这种写法并不优雅,index.js对于math.js没有控制权,能不能调用到add()函数完全取决于自己的html有没有正确的引入math.js。
所以这边就产生了几个问题:1.index.js无法import,依赖html的引用2.index.js中无法对add方法的来源做区别分,缺少命名空间的概念3.Js中只有两种作用域,一个是函数作用域,当函数执行完后变量会释放。而一个是全局作用域,从页面打开到关闭的过程中,变量会一直存在,就会造成全局变量的污染,所以js模块化编程很重要初步模块化
解决第二个问题,也就是命名空间的概念。
我们把math中的函数放进去一个以math命名的对象中,这样就形成了一个简易版的命名空间了。math.js
var math = { base: 5, add: function(a,b){ return a + b; },};
index.js
function Girl(){ var p = document.getElementById("boy"); p.innerHTML = math.add(1,2);//我们知道了这个方法来自math这个文件}
但是这里math对象中的另一个属性base也会被暴露和修改,因此我们升级一下。
math.js
var math = (function(){ var base = 7; return { add: function(a,b){ return a + b + base; }, };})();
我们把math定义在一个闭包中,从而隐藏了内部属性。
index.jsfunction Girl(){ var p = document.getElementById("boy"); p.innerHTML = math.add(1,2); document.write(math.base);//undefine}
到目前为止,我们完成了模块的简易定义与使用。但是模块化的一大精髓是命名空间,就是按需导入,而此时math却是一个全局变量。因此我们可以引入中间件来解决这个问题。
引入中间件
我们定义一个全局变量
global.js
var module = { export: {}}
在math.js中
var math = (function(){ var base = 7; return { add: function(a,b){ return a + b + base; }, };})();mmodule.export.math = math;//把math注册
index.js
var math = module.export.math;//指定了math.js中的math方法function Girl(){ var p = document.getElementById("boy"); p.innerHTML = math.add(1,2);}