@@ -441,17 +441,15 @@ JavaScript中的回调模式已经是我们的家常便饭了,比如,如果
441441从结果来看,当重定义函数被赋值给一个新的变量的时候,这段使用重定义函数的代码的执行结果与我们期望的结果可能并不一样。每当` prank() ` 被调用的时候,它都弹出“Boo!”。同时它也重写了` scareMe() ` 函数,但是` prank() ` 自己仍然能够使用之前的定义,包括属性` property ` 。在这个函数被作为` spooky ` 对象的` boo() ` 方法调用的时候,结果也一样。所有的这些调用,在第一次的时候就已经修改了全局的` scareMe() ` 的指向,所以当它最终被调用的时候,它的函数体已经被修改为弹出“Double boo”,也就不能获取到新添加的属性` scareMe.property ` 。
442442
443443
444- ---------校对分割线---------
445- <a name =" a15 " ></a >
446- ## 立即执行的函数
444+ ## 即时函数
447445
448- 立即执行的函数是一种语法模式 ,它会使函数在定义后立即执行。看这个例子:
446+ 即时函数是一种语法模式 ,它会使函数在定义后立即执行。看这个例子:
449447
450448 (function () {
451449 alert('watch out!');
452450 }());
453451
454- 这种模式本质上只是一个在创建后就被执行的函数表达式(具名或者匿名)。“立即执行的函数 ”这种说法并没有在ECMAScript标准中被定义,但它作为一个名词,有助于我们的描述和讨论。
452+ 这种模式本质上只是一个在创建后就被执行的函数表达式(具名或者匿名)。“即时函数 ”这种说法并没有在ECMAScript标准中被定义,但它作为一个名词,有助于我们的描述和讨论。
455453
456454这种模式由以下几个部分组成:
457455
@@ -465,7 +463,7 @@ JavaScript中的回调模式已经是我们的家常便饭了,比如,如果
465463 alert('watch out!');
466464 })();
467465
468- 这种模式很有用,它为我们提供一个作用域的沙箱,可以在执行一些初始化代码的时候使用。设想这样的场景:当页面加载的时候,你需要运行一些代码,比如绑定事件、创建对象等等。所有的这些代码都只需要运行一次,所以没有必要创建一个带有名字的函数。但是这些代码需要一些临时变量,而这些变量在初始化完之后又不会再次用到 。显然,把这些变量作为全局变量声明是不合适的。正因为如此,我们才需要立即执行的函数 。它可以把你所有的代码包裹到一个作用域里面,而不会暴露任何变量到全局作用域中:
466+ 这种模式很有用,它为我们提供一个作用域的沙箱,可以在执行一些初始化代码的时候使用。设想这样的场景:当页面加载的时候,你需要运行一些代码,比如绑定事件、创建对象等等。所有的这些代码都只需要运行一次,所以没有必要创建一个带有名字的函数。但是这些代码需要一些临时变量,而这些变量在初始化完之后又不会再次被用到 。显然,把这些变量作为全局变量声明是不合适的。正因为如此,我们才需要即时函数 。它可以把你所有的代码包裹到一个作用域里面,而不会暴露任何变量到全局作用域中:
469467
470468 (function () {
471469
@@ -477,13 +475,14 @@ JavaScript中的回调模式已经是我们的家常便饭了,比如,如果
477475
478476 }()); // "Today is Fri, 13"
479477
480- 如果这段代码没有被包裹到立即执行函数中,那么变量days、 today、msg都会是全局变量,而这些变量仅仅是由因为初始化而遗留下来的垃圾 ,没有任何用处。
478+ 如果这段代码没有被包裹到立即执行函数中,那么变量 ` days ` 、 ` today ` 、 ` msg ` 都会是全局变量,而这些变量仅仅是因为初始化而遗留下来的垃圾 ,没有任何用处。
481479
482480
481+ ---------校对分割线---------
483482<a name =" a16 " ></a >
484- ### 立即执行的函数的参数
483+ ### 即时函数的参数
485484
486- 立即执行的函数也可以接受参数 ,看这个例子:
485+ 即时函数也可以接受参数 ,看这个例子:
487486
488487 // prints:
489488 // I met Joe Black on Fri Aug 13 2010 23:26:59 GMT-0800 (PST)
@@ -494,14 +493,14 @@ JavaScript中的回调模式已经是我们的家常便饭了,比如,如果
494493
495494 }("Joe Black", new Date()));
496495
497- 通常的做法,会把全局对象当作一个参数传给立即执行的函数 ,以保证在函数内部也可以访问到全局对象,而不是使用window对象,这样可以使得代码在非浏览器环境中使用时更具可移植性。
496+ 通常的做法,会把全局对象当作一个参数传给即时函数 ,以保证在函数内部也可以访问到全局对象,而不是使用window对象,这样可以使得代码在非浏览器环境中使用时更具可移植性。
498497
499- 值得注意的是,一般情况下尽量不要给立即执行的函数传入太多的参数 ,否则会有一件麻烦的事情,就是你在阅读代码的时候需要频繁地上下滚动代码。
498+ 值得注意的是,一般情况下尽量不要给即时函数传入太多的参数 ,否则会有一件麻烦的事情,就是你在阅读代码的时候需要频繁地上下滚动代码。
500499
501500<a name =" a17 " ></a >
502- ### 立即执行的函数的返回值
501+ ### 即时函数的返回值
503502
504- 和其它的函数一样,立即执行的函数也可以返回值 ,并且这些返回值也可以被赋值给变量:
503+ 和其它的函数一样,即时函数也可以返回值 ,并且这些返回值也可以被赋值给变量:
505504
506505 var result = (function () {
507506 return 2 + 2;
@@ -521,9 +520,9 @@ JavaScript中的回调模式已经是我们的家常便饭了,比如,如果
521520 return 2 + 2;
522521 })();
523522
524- 前面的例子中,立即执行的函数返回的是一个基本类型的数值 。但事实上,除了基本类型以外,一个立即执行的函数可以返回任意类型的值 ,甚至返回一个函数都可以。你可以利用立即执行的函数的作用域来存储一些私有的数据 ,这些数据只能在返回的内层函数中被访问。
523+ 前面的例子中,即时函数返回的是一个基本类型的数值 。但事实上,除了基本类型以外,一个即时函数可以返回任意类型的值 ,甚至返回一个函数都可以。你可以利用即时函数的作用域来存储一些私有的数据 ,这些数据只能在返回的内层函数中被访问。
525524
526- 在下面的例子中,立即执行的函数的返回值是一个函数 ,这个函数会简单地返回res的值,并且它被赋给了变量getResult。而res是一个预先计算好的变量,它被存储在立即执行函数的闭包中:
525+ 在下面的例子中,即时函数的返回值是一个函数 ,这个函数会简单地返回res的值,并且它被赋给了变量getResult。而res是一个预先计算好的变量,它被存储在立即执行函数的闭包中:
527526
528527 var getResult = (function () {
529528 var res = 2 + 2;
@@ -532,7 +531,7 @@ JavaScript中的回调模式已经是我们的家常便饭了,比如,如果
532531 };
533532 }());
534533
535- 在定义一个对象的属性的时候也可以使用立即执行的函数 。设想一下这样的场景:你需要定义一个对象的属性,这个属性在对象的生命周期中都不会改变,但是在定义之前,你需要做一点额外的工作来得到正确的值。这种情况下你就可以使用立即执行的函数来包裹那些额外的工作 ,然后将它的返回值作为对象属性的值。下面是一个例子:
534+ 在定义一个对象的属性的时候也可以使用即时函数 。设想一下这样的场景:你需要定义一个对象的属性,这个属性在对象的生命周期中都不会改变,但是在定义之前,你需要做一点额外的工作来得到正确的值。这种情况下你就可以使用即时函数来包裹那些额外的工作 ,然后将它的返回值作为对象属性的值。下面是一个例子:
536535
537536 var o = {
538537 message: (function () {
@@ -555,13 +554,13 @@ JavaScript中的回调模式已经是我们的家常便饭了,比如,如果
555554<a name =" a18 " ></a >
556555### 好处和用法
557556
558- 立即执行的函数应用很广泛 。它可以帮助我们做一些不想留下全局变量的工作。所有定义的变量都只是立即执行的函数的本地变量 ,你完全不用担心临时变量会污染全局对象。
557+ 即时函数应用很广泛 。它可以帮助我们做一些不想留下全局变量的工作。所有定义的变量都只是即时函数的本地变量 ,你完全不用担心临时变量会污染全局对象。
559558
560- > 立即执行的函数还有一些名字 ,比如“自调用函数”或者“自执行函数”,因为这些函数会在被定义后立即执行自己。
559+ > 即时函数还有一些名字 ,比如“自调用函数”或者“自执行函数”,因为这些函数会在被定义后立即执行自己。
561560
562561这种模式也经常被用到书签代码中,因为书签代码会在任何一个页面运行,所以需要非常苛刻地保持全局命名空间干净。
563562
564- 这种模式也可以让你包裹一些独立的特性到一个封闭的模块中。设想你的页面是静态的,在没有JavaScript的时候工作正常,然后,本着渐进增强的精神,你给页面加入了一点增加代码。这时候,你就可以把你的代码(也可以叫“模块”或者“特性”)放到一个立即执行的函数中并且保证页面在有没有它的时候都可以正常工作 。然后你就可以加入更多的增强特性,或者对它们进行移除、进行独立测试或者允许用户禁用等等。
563+ 这种模式也可以让你包裹一些独立的特性到一个封闭的模块中。设想你的页面是静态的,在没有JavaScript的时候工作正常,然后,本着渐进增强的精神,你给页面加入了一点增加代码。这时候,你就可以把你的代码(也可以叫“模块”或者“特性”)放到一个即时函数中并且保证页面在有没有它的时候都可以正常工作 。然后你就可以加入更多的增强特性,或者对它们进行移除、进行独立测试或者允许用户禁用等等。
565564
566565你可以使用下面的模板定义一段函数代码,我们叫它module1:
567566
@@ -578,7 +577,7 @@ JavaScript中的回调模式已经是我们的家常便饭了,比如,如果
578577<a name =" a19 " ></a >
579578## 立即初始化的对象
580579
581- 还有另外一种可以避免污染全局作用域的方法,和前面描述的立即执行的函数相似 ,叫做“立即初始化的对象”模式。这种模式使用一个带有init()方法的对象来实现,这个方法在对象被创建后立即执行。初始化的工作由init()函数来完成。
580+ 还有另外一种可以避免污染全局作用域的方法,和前面描述的即时函数相似 ,叫做“立即初始化的对象”模式。这种模式使用一个带有init()方法的对象来实现,这个方法在对象被创建后立即执行。初始化的工作由init()函数来完成。
582581
583582下面是一个立即初始化的对象模式的例子:
584583
@@ -607,7 +606,7 @@ JavaScript中的回调模式已经是我们的家常便饭了,比如,如果
607606 ({...}).init();
608607 ({...}.init());
609608
610- 这种模式的好处和自动执行的函数模式是一样的:在做一些一次性的初始化工作的时候保护全局作用域不被污染。从语法上看,这种模式似乎比只包含一段代码在一个匿名函数中要复杂一些,但是如果你的初始化工作比较复杂(这种情况很常见),它会给整个初始化工作一个比较清晰的结构。比如,一些私有的辅助性函数可以被很轻易地看出来,因为它们是这个临时对象的属性,但是如果是在立即执行的函数模式中 ,它们很可能只是一些散落的函数。
609+ 这种模式的好处和自动执行的函数模式是一样的:在做一些一次性的初始化工作的时候保护全局作用域不被污染。从语法上看,这种模式似乎比只包含一段代码在一个匿名函数中要复杂一些,但是如果你的初始化工作比较复杂(这种情况很常见),它会给整个初始化工作一个比较清晰的结构。比如,一些私有的辅助性函数可以被很轻易地看出来,因为它们是这个临时对象的属性,但是如果是在即时函数模式中 ,它们很可能只是一些散落的函数。
611610
612611这种模式的一个弊端是,JavaScript压缩工具可能不能像压缩一段包裹在函数中的代码一样有效地压缩这种模式的代码。这些私有的属性和方法不被会重命名为一些更短的名字,因为从压缩工具的角度来看,保证压缩的可靠性更重要。在写作本书的时候,Google出品的Closure Compiler的“advanced”模式是唯一会重命名立即初始化的对象的属性的压缩工具。一个压缩后的样例是这样:
613612
@@ -1015,7 +1014,7 @@ step 1是一个所谓的部分应用的例子:我们只应用了第一个参
10151014
10161015 新函数在已有函数的基础上再加上一部分参数构成
101710162 . 初始化模式,这些模式帮助我们用一种干净的、结构化的方法来做一些初始化工作(在web页面和应用中非常常见),通过一些临时变量来保证不污染全局命名空间。这些模式包括:
1018- - 立即执行的函数
1017+ - 即时函数
10191018
10201019 当它们被定义后立即执行
10211020 - 立即初始化的对象
0 commit comments