现在的网页越来越大,功能也越来越全,我们已经无法像五六年前那样简单的切割图就能实现业务的需求了。网站的功能越来越强大,甚至超越了某些桌面程序。
曾经作为网页特效的js,在如今也显得愈加重要。可如果还是按照曾经按部就班的过程化编写,工作量实在太大,现代前端开发方式中很重要的一个特点就是协作。一个开发者只要书写核心内容,其余的功能加载别人写好的模块即可,那么问题来了,什么是模块?
模块就是实现某种功能的一组方法
1、最简单直白的模块
函数可以解决一个小功能,变量也能协助解决问题,那么函数和变量放在一起就能变成一个模块,比如module1:
var a=0; function b(){ } function c(){ }
上面的module1就是一个模块了,但是,这个模块很容易造成 “变量污染” ,比如变量a或者函数b等等的名字或许会和别的模块内变量和函数名冲突。
2、利用对象实现一个模块
利用单例模式的思维,我们声明一个对象,把变量和函数都放到对象中,就像module2:
var module2=new Object(){ a:0, b:function(){ }, c:function(){ } }
上面的方式看起来更好了,因为我们大大降低了变量污染的可能。但是新的问题出现了,这种方式导致我们模块内部成员的暴露从而很容易被外部篡改,比如:
module2.a=1
简单一句话,module2内部的a属性值就被修改掉了,甚至b、c这样的方法也可能被外界覆盖掉。
3、自执行函数实现模块
为了解决成员暴露的问题,我们使用一个自执行函数来实现模块module3
var module3=(function(){ var a=0; var b=function(){ }; var c=function(){ }; return { b:b, c:c } })()
这样我们的模块内部就无法在被人访问到了,这也就是一个模块最原始的状态。
4、模块的依赖(传入全局变量)
实际开发应用中我们往往不止使用一个模块,某一个复杂功能很可能需要多个模块协作才能完成,那么如何实现这样的功能呢?
在module3的设计中,我们使用了自执行函数,既然是函数,那么就可以传参,试试这样呢?
//上面的两个函数放在一起就能实现一个模块。不过这样做的坏处在于产生了变量 var module4=(function(mod){ //书写module4自己的功能 var d=1; var e=function(){ //借用module3解决一个问题 mod.b(); }; return { d:d, e:e } })(module3);
在构建module4的过程中,我们借用了module3模块,这就是模块之间的关联,使用了功能,但相互是独立的,互不影响。这也叫模块依赖。
5、宽放大模式
举个例子,实际开发过程中,你的模块可能是好些人在做,那么也代表这个模块有好多部分,此时我们可以使用宽放大模式
//在使用过程中更新module4的功能 var module4=(function(mod){ //为module4作一个addFn的扩展 mod.addFn=function(){ }; //返回新的module4 return mod; })(window.module4 || {});
上面的代码中,自执行函数传参我们增加了一个{}空对象,这有什么好处呢?(注意,所有这个模块的开发者都需要用这种写法)
我们知道,js的一大特点就是异步加载执行,使用了这样的方式以后,我们可以想象:张同学的js文件中有一个module4模块,李同学的js文件中有一个module4模块,王同学也有一个module4模块,这时候谁的module4先加载出来有区别么?所有文件都会在加载出来后立刻执行,先寻找window上的module4对象,如果没有的话传入一个{}空对象,进一步修改之后生成一个module4文件,后续还用说么?