先来看一段代码:
//原始写法
function test1(){
alert("aaa");
}
function test1(){
alert("bbb");
}
test1();
在这个示例中,定义了两个重名的函数,调用的时候会选择后面那个。这是开发中最原始的写法。
多人开发的时候,因为内容太多,经常可能会定义相同的函数名,以致于前面相同函数名的函数会失效。也因为要编写的函数太多,以致于最后哪个函数对应哪些功能,或是谁编写的,可能都不清晰。
//自执行函数写法
var ch_init = (function(){
var a_ch = function(){ alert("a_ch");}
var b_ch = function(){ alert("b_ch");}
return {
a_ch:a_ch,
b_ch:b_ch
};
})();
//自执行函数写法
var fh_approval = (function(){
var a_ch = function(){alert("a_fh")};
var b_ch = function(){alert("b_fh")};
return {
a_ch:a_ch,
b_ch:b_ch
};
})();
ch_init.a_ch();
ch_init.b_ch();
fh_approval.a_ch();
fh_approval.b_ch();
ch_init和fh_approval都是一个自动执行的函数。在一个函数内部定义了其他函数,然后返回定义的这些内部函数。这是js的闭包写法。两个自执行函数内部的函数名称可以重复,不会覆盖前面的。
以上两张图片的代码都是模块化的写法。模块化指的是实现特定功能的一组方法。模块化有很多种形式。
//对象写法
var callInnerFunction = new Object({
count:0,
mul:function(){ this.count = this.count * 2},
add:function(){ count = count + 2}
});
callInnerFunction.count = callInnerFunction.count + 2;
callInnerFunction.mul();
alert(callInnerFunction.count);
这种方式在函数的外部可以修改函数内部的变量,暴露了内部成员。而上一种方式则很好地避免了从外部修改内部成员。
模块化在不断的发展和演进。如果想要拓展修改其他人写的代码,可以采取放大模式或宽放大模式。放大模式是向其中注入需要拓展的函数名称。
当需要加载的模块较多,为了避免有的模块加载比较慢出现注入了一个空对象,可以在传入参数中添加一个空对象。
模拟一个慢加载的情况,将拓展函数放在注入函数之前,如果是放大模式,在ch_init.c_ch这一行就会出现错误。
//放大模式
var extend = (function(ch_init){
ch_init.c_ch = function(){
console.log("extend c_ch");
};
return ch_init;
})(window.ch_init);
如果是宽放大模式,则可以“包容”这个错误。
//宽放大模式
var extend = (function(ch_init){
ch_init.c_ch = function(){
console.log("extend c_ch");
};
return ch_init;
})(window.ch_init|| {});
运行过程不会出现错误。但是如果调用ch_init.c_ch()则是不行的。因为你把c_ch是挂在空对象上,只是运行的时候兼容了这个错误。
再来谈谈模块的独立性,如果一个模块内部想要使用其他库的东西最好采用注入的方式,而不是直接调用,这样可以更清楚地看出模块与其他库的关系。大家可以思考下这个和Spring的DI依赖注入是不是有同工之妙。
推荐大家读一下阮一峰的这篇博客,我的分享是建立在这篇文章的基础上的,哪里写的有误或是大家有什么见解都可以向我指出。
http://www.ruanyifeng.com/blog/2012/10/javascript_module.html
JavaScript模块化编程(一):模块的写法