一、原始写法
/*
模块就是实现特定功能的一组方法。
只要把不同的函数(以及记录状态的变量)简单地放在一起,就算是一个模块。
上面的函数m1()和m2(),组成一个模块。使用的时候,直接调用就行了。
这种做法的缺点很明显:"污染"了全局变量,
无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。
*/
var aaa = 'aa';
function m1() {
console.log(aaa);
aaa = 'cc';
}
function m2() {
console.log(aaa);
}
m1();//aa
m2();//cc
二、对象写法
/*
为了解决上面的缺点,可以把模块写成一个对象,所有的模块成员都放到这个对象里面。
上面的函数m1()和m2(),都封装在module1对象里。使用的时候,就是调用这个对象的属性。
但是,这样的写法会暴露所有模块成员,内部状态可以被外部改写。比如,外部代码可以直接改变内部计数器的值。
*/
var module1 = new Object({
aaa:'aaa',
m1: function() {
console.log(this.aaa);
},
m2: function() {
}
});
module1.m1();//aaa
module1.aaa='bbb';
module1.m1();//bbb
三、立即执行函数写法
/*
使用"立即执行函数",可以达到不暴露私有成员的目的。
*/
var module1 = (function() {
var aaa = 'aaa';
var m1 = function() {
console.log(aaa)
};
var m2 = function() {
//...
};
return {
m1: m1,
m2: m2
};
})();
module1.m1();//aaa
console.log(module1.aaa);//undefined
//立即执行函数
(function(){
//...
}());
//可以拆解为
function a(){
//...
}
a();
四、放大模式
/*
如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用"放大模式"(augmentation)。
*/
var module1 = (function() {
var aaa = 'aaa';
var m1 = function() {
console.log(aaa);
};
var m2 = function() {
//...
};
return {
m1: m1,
m2: m2
};
})();
var module1 = (function(mod) {
mod.m3 = function() {
console.log('m3');
};
return mod;
})(module1);
module1.m1();//aaa
module1.m3();//m3 调用不了aaa
五、宽放大模式
/*
独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互。
为了在模块内部调用全局变量,必须显式地将其他变量输入模块。
*/
var module1 = (function() {
var m1 = function() {
console.log('m1');
};
var m2 = function() {
//...
};
return {
m1: m1,
m2: m2
};
})();
var module2 = (function() {
var m21 = function() {
console.log('m21');
};
var m22 = function() {
//...
};
return {
m21: m21,
m22: m22
};
})();
var module3 = (function(module1, module2) {
var m31 = function() {
module1.m1();
};
var m32 = function() {
module2.m21();
};
return {
m31: m31,
m32: m32
};
})(module1, module2);
module3.m31(); //m1
module3.m32(); //m21