所谓的模块化编程就是封装细节,提供使用接口,彼此之间互不影响,每个模块都是相互独立,实现某一特定的功能。如果其他模块想调用的时候,可以暴露我们所希望对外的公开的方法与数据。
1、函数写法
function f1(){ var value=1; //... } function f2(){ var value=2; //... }
这里定义了f1跟f2,每个函数相当于一个模块,f1跟f2是相互独立的,不能访问到对方里面的局部内容value;这种写法定义了全局变量f1、f2污染了全局环境会导致命名冲突(在上一篇文章提过)。
2、对象写法
var myModule= new Object({ value : 0, f1 : function (){ //... }, f2 : function (){ //... } });
把函数f1()和f2(),封装在myModule对象里。使用的时候,就是调用这个对象的属性即可:myModule.f1()。这样的写法会暴露所有模块成员,内部状态可以被外部改写如:myModule.value=1 ,会改变myModule内部的属性值。同时这种办法只能一定程度上减少了命名冲突的问题,不能完全避免命名冲突。
3、立即执行函数写法
(1)匿名闭包写法
(function () { // ... }());
javascript中没用私有作用域的概念,根据javascript函数作用域链的特性,使用这种写法可以模仿一个私有作用域。在闭包中,可以定义私有变量和函数,外部无法访问它们,从而做到了私有成员的隐藏和隔离,俗称“匿名包裹器”或“命名空间”。
(2)全局引入写法
(function (a) { a.a3 = function () { //... }; // … }(a));
将a对象作为参数传入,在函数体内对这个对象进行操作。这样做除了保证模块的独立性,还使得模块之间的依赖关系变得明显。现在很多类库里都有这种使用方式,比如jQuery源码。
(3)模块导出写法
var myModule = (function(){
var value = 0; var f1 = function(){ //... }; var f2 = function(){ //... }; return { value: value, f2 : f2 }; })();
这里,我们声明了一个全局的模块叫myModule,它包含二个属性,一个成员变量value和一个成员方法f1。除此之外,它还使用匿名函数的闭包维护了私有内部状态,我们也可以通过按需传入外部变量。
(3)扩展模式写法
var myModule = (function (a) { var value =a.value; var f1 = function(){ //... }; var f2 = function(){ //... }; return { value: value, f2 : f2 }; }(a));
这里,我们在闭包中定义私有变量和函数,外部无法访问它们,做到了私有成员的隐藏和隔离。将某对象作为参数传入,在函数体内对该对象进行操作,然后返回对象或函数。由此,可以做到把依赖项通过参数的形式注入进来在内部使用注入的属性,并且可以暴露我们所希望对外的公开的方法与数据。这就是模块化编程的基础思想。
在此思想之下,javaScript模块化编程开始盛行,大牛们开始进行各式各样的封装打包,从而产出一系列的模块化规范、模块化加载器。上面的方法中,a必须在模块myModule之前定义,如果a依赖项自身是一个大的模块,比如一个库,我们如何做到在myModule之前定义加载a,然后在myModule中成功地引用a呢?模块化加载器便能帮我们解决这个问题。
下一篇我们开始介绍模块化规范的先驱-------CommonJS规范;