在JS中,因为 变量的定义 只有 全局变量 和 局部变量(局部变量是放在 函数中),而全局变量,在JS中任何地方都能访问到,所以 很容易 出现 变量的污染,同时,当有多人 开发时,很容易出现 函数名相同,这样当进行函数调用时,会出现冲突,
当一个JS文件中有很多函数,但是页面不一定会使用所以的函数,此时加载JS文件,会大大的浪费内存,也浪费时间,所以 会把大的JS文件分割成多个小的JS文件,把一个JS文件看成一个模块,但是模块与模块之间可能存在依赖关系,如果在页面上引入一个个的
JS文件,当经常进行变动时,会大量的对引入JS进行修改,这些依赖可以通过Javascript模块规范:CommonJS和AMD等 来搞定。
JS 模块化就是 针对 JS 中的 冲突,性能, 依赖 来进行优化的。
JavaScript的作用域就是基于函数的,所以把函数作为模块化的第一步是很自然的事情,在一个文件里面编写几个相关函数就是最开始的模块了,刚开始的时候我们写js代码是这么写的
function method1(){ } function method2(){ }
函数method1()和method2(),组成一个模块。使用的时候,直接调用就行了。写法是有很明显的缺陷的, 这个在页面上我们可能引用了其他的js库,这么写会污染全局变量,无法保证自己定义的函数名称不同其他js库中的名字冲突。而且也不能看出不同函数之间的关系。
二、对象写法
为了解决上面的缺点,可以把模块写成一个对象,所有的模块成员都放到这个对象里面,相当于是 把这些放在一个命名空间中,
var module = { a : 0, b : 1, method1:function(){ }, method2:function(){ } }
此时 函数 method1 和 method2 都封装在 对象 module 中,如果调用,就是相当于使用对象的属性:
module.method1(); module.method2()
如此将相关函数放入一个模块内部可以大大的减少名字冲突的概率,但是如此写也会有一个缺点,模块内部的一些内部状态也对外可见,我们可以在外部修改其内部状态
module.a = 3; 此时就修改了module 中的属性a,内部状态可以被外部改写
三、立即执行函数写法
函数定义完,就进行执行,如此一来我们就将内部变量隔绝在模块内部,只有内部函数才能访问以及赋值,从模块外部无法进行访问。可以达到不暴露私有成员的目的
var module = (function(){ var a = 0; var method1 = function(){}; var method2 = function(){}; return{ method1:method1, method2:mehtod2 }; })();
模块外部无法访问内部的函数和变量:
console.info(module.a); //undefined
四、放大模式
如果某个模块过大,那么怎么办呢?把所有的内容放在同一个js文件中么,这样在加载js文件的时候就会加载了本来不需要的内容,照成网络资源的浪费。
var module = (function(mod){ mod.method3 = function(){ //... }
return mod; })(module);
这个 就是 给 module模块添加了一个method3方法,返回新的module模块
五、宽放大模式(Loose augmentation)
模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上一节的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用"宽放大模式"。
var module = (function(mod){ mod.method3 = function(){ //... } })(module||{});
与"放大模式"相比,"宽放大模式"就是"立即执行函数"的参数可以是空对象。