大家都知道,js中的变量(variable)有其作用范围,比如:函数里用var定义的变量在函数外是看不到的,而定义在函数外面的变量(不能有没有var修饰)均是全局变量,在js程序的任何位置都可以访问。嗯,实际上我们在工作过程中,业务逻辑比较多,而一个业务逻辑包含多个函数,函数之间共享使用某个变量,这样问题就来了,如果另外一个业务逻辑不小心定义了或者修改了这个变量,就会造成这个全局变量被污染,前一个业务逻辑就会出现脏读,过程测试如下:
一个很长的页面脚本程序包含两个子业务处理过程1和2,业务处理程序1需要定义两个函数和一个变量,一个函数设置变量,一个函数读取输出变量,如下:
1 /*****页面业务逻辑1***begin*****/
2
3 //定义一个全局变量,供逻辑1中的各函数共享使用
4 var test = 0;
5 function setFlag() {
6 test = 1;
7 }
8 function displayFlag() {
9 console.log(test);
10 }
11
12 /*****页面业务逻辑1***end*****/
其他业务处理程序脚本:
1 /*
2 * ……………………………………
3 * 中间业务逻辑,篇幅很长
4 * ……………………………………
5 */
业务处理程序2开始,逻辑处理也定义了两个函数和一个变量,一个函数设置变量,一个函数读取变量进行其他处理,不幸的是,这个全局变量采用了同业务逻辑1相同的名字:
1 /*****页面业务逻辑2***begin*****/
2
3 //定义一个全局变量,供逻辑1中的各函数共享使用
4 var test = 0;
5 function setVarable() {
6 test = 1;
7 }
8 function displayV() {
9 console.log(test);
10 }
11
12 /*****页面业务逻辑2***end*****/
程序过程在进行逻辑2后再进行逻辑1,此时出现了意外:
1 setVarable(); //逻辑2不小心修改了该值
2
3 displayFlag(); //error:预期输出1,但是却脏读成了2
输出结果如下:
很明显,实际输出的结果并不是期望的结果,此外还有另外一种情况,如果某个js脚本程序被共享为一个共用的脚本块,在多个地方调用(引入)这个脚本块时,也会很容易出现这个问题。
而模块化编程(Module)的出现就解决了这个问题,除此之外模块化编程还有其他几个特点:
1. 维护一个干净前端脚本的变量环境,保护一定作用范围内定义的全局变量不被范围外程序的污染;
2. 前端脚本程序的可重用性大大提高,可读性和可维护性进一步增强;
3. 可以组合多个module脚本,抽象成一个公共的脚本库,提高代码的开发效率;
前面说过,函数内部定义的变量函数外看不到(即不可用),为了保护变量环境的作用域,这正是我们需要的结果,故把整个业务处理逻辑扔到一个函数里实现就可以实现一个模块的定义,改写上面逻辑1和逻辑2的代码如下:
1 /*****页面业务逻辑1********/
2 function HandleOne() {
3 var test = 0;
4 this.setFlag = function() {
5 test = 1;
6 }
7 this.displayFlag = function() {
8 console.log("这是逻辑1中的变量值:" + test);
9 }
10 //返回this对象,以访问module里定义的函数
11 return this;
12 }
13
14 /*
15 * ……………………………………
16 * 中间业务逻辑,篇幅很长
17 * ……………………………………
18 */
19
20 /*****页面业务逻辑2********/
21 function HandleTwo() {
22 var test;
23 this.setVarable = function() {
24 test = 2;
25 }
26 this.displayV = function() {
27 console.log("这是逻辑2中的变量值:" + test);
28 }
29 //返回this对象,以访问module里定义的函数
30 return this;
31 }
32
33 var H1 = HandleOne();
34 var H2 = HandleTwo();
35
36 H2.setVarable(); //逻辑2修改了自己的变量
37
38 H1.displayFlag(); //逻辑1输出自己的变量
39
40 H2.displayV(); //逻辑2输出自己的变量
输出结果如下:
由上图可知,在模块化编程下,每个模块内部使用的共用变量都很好的被保护起来了,不在收到外面其他逻辑处理的干扰,但是上述过程需要我们定义两个函数模块,如果我们不想额外定义任何中间变量,我们可以采用匿名函数来重新实现上述过程,代码改写如下:
1 /*****页面业务逻辑1********/
2 var H1 = (function() {
3 var test = 0;
4 this.setFlag = function() {
5 test = 1;
6 }
7 this.displayFlag = function() {
8 console.log("这是逻辑1中的变量值:" + test);
9 }
10 //返回this对象,以访问module里定义的函数
11 return this;
12 } ());
13
14 /*
15 * ……………………………………
16 * 中间业务逻辑,篇幅很长
17 * ……………………………………
18 */
19
20 /*****页面业务逻辑2********/
21 var H2 = (function() {
22 var test;
23 this.setVarable = function() {
24 test = 2;
25 }
26 this.displayV = function() {
27 console.log("这是逻辑2中的变量值:" + test);
28 }
29 //返回this对象,以访问module里定义的函数
30 return this;
31 } ());
32
33 H2.setVarable(); //逻辑2修改了自己的变量
34
35 H1.displayFlag(); //逻辑1输出自己的变量
36
37 H2.displayV(); //逻辑2输出自己的变量
上面的是用匿名函数实现的模块化封装,输出的结果同实体函数时一样,是不是比实体函数时更加简洁了?!
注:上述过程中我们在每个模块中返回了this对象,是因为我们需要在后续的逻辑中调用该模块中的函数,如果在实践过程中模块处理程序不需要被外部逻辑调用,而只是在模块内部输出结果即可的话,我们只需返回模块最终处理的结果值或者不需要返回语句,依据具体情况具体分析。
通过上述的例子我们可以总结出模块化的一般思路:
1. 把相关联的一系列函数及变量的定义放在一个函数(匿名函数也行)中即可形成一个模块,模块中的变量和函数的作用域仅限于模块内部,外部无法直接调用,模块可以返回既定逻辑的处理结果。
2. 如果需要在模块外部提供调用模块中函数或者变量的接口,则需要将模块中函数或变量的定义用this标记,然后在模块最后返回这个this对象(函数中的this对象指的是window对象)。
模块化的编程思路如下:
1 //实体函数时的模块化思路
2 function Moudle() {
3
4 var theResult;
5
6 //do something here
7
8 //这一句可有可无,有则返回最终的处理结果
9 return theResult;
10 }
11 //执行模块过程,有返回值时可以接收返回值
12 Moudle();
13
14 //匿名函数时的模块化思路
15 var result = (function() {
16 var theResult;
17
18 //do something here
19
20 //这一句可有可无,有则返回最终的处理结果
21 return theResult;
22 });
文章来自http://www.360doc.com/content/15/0810/21/27084883_490826869.shtml