复习JavaScript 5

立即调用的函数表达式 复习

函数的执行上下文

>在JavaScript里,任何function在执行的时候都会创建一个执行上下文,因为为function声明的变量和声明的function有可能只在该function内部。

  1. // 由于该function里返回了另外一个function,其中这个function可以访问*变量i
  2. // 所有说,这个内部的function实际上是有权限可以调用内部的对象。
  3. function makeCounter() {
  4. // 只能在makeCounter内部访问i
  5. var i = 0;
  6. return function () {
  7. console.log(++i);
  8. };
  9. }
  10. // 注意,counter和counter2是不同的实例,分别有自己范围内的i。
  11. var counter = makeCounter();
  12. counter(); // logs: 1
  13. counter(); // logs: 2
  14. var counter2 = makeCounter();
  15. counter2(); // logs: 1
  16. counter2(); // logs: 2
  17. alert(i); // 引用错误:i没有defind(因为i是存在于makeCounter内部)。

自执行函数表达式

之前的提过函数表达式可以立即运行,类似下面:

  1. // 下面2个括弧()都会立即执行
  2. (function () { /* code */ } ()); // 推荐使用这个
  3. (function () { /* code */ })(); // 但是这个也是可以用的
  4. // 由于括弧()和JS的&&,异或,逗号等操作符是在函数表达式和函数声明上消除歧义的
  5. // 所以一旦解析器知道其中一个已经是表达式了,其它的也都默认为表达式了
  6. // 不过,请注意下一章节的内容解释
  7. var i = function () { return 10; } ();
  8. true && function () { /* code */ } ();
  9. 0, function () { /* code */ } ();
  10. // 如果你不在意返回值,或者不怕难以阅读
  11. // 你甚至可以在function前面加一元操作符号
  12. !function () { /* code */ } ();
  13. ~function () { /* code */ } ();
  14. -function () { /* code */ } ();
  15. +function () { /* code */ } ();
  16. // 还有一个情况,使用new关键字,也可以用,但我不确定它的效率
  17. // http://twitter.com/kuvos/status/18209252090847232
  18. new function () { /* code */ }
  19. new function () { /* code */ } () // 如果需要传递参数,只需要加上括弧()

闭包的神奇

自执行的函数表达式当然也是函数,所以它理所应当可以传入参数。闭包的神奇就在于它可以有效地保存闭包内的状态。

  1. // 这个代码是错误的,因为变量i从来就没背locked住
  2. // 相反,当循环执行以后,我们在点击的时候i才获得数值
  3. // 因为这个时候i操真正获得值
  4. // 所以说无论点击那个连接,最终显示的都是I am link #10(如果有10个a元素的话)
  5. var elems = document.getElementsByTagName(‘a‘);
  6. for (var i = 0; i < elems.length; i++) {
  7. elems[i].addEventListener(‘click‘, function (e) {
  8. e.preventDefault();
  9. alert(‘I am link #‘ + i);
  10. }, ‘false‘);
  11. }
  12. // 这个是可以用的,因为他在自执行函数表达式闭包内部
  13. // i的值作为locked的索引存在,在循环执行结束以后,尽管最后i的值变成了a元素总数(例如10)
  14. // 但闭包内部的lockedInIndex值是没有改变,因为他已经执行完毕了
  15. // 所以当点击连接的时候,结果是正确的
  16. var elems = document.getElementsByTagName(‘a‘);
  17. for (var i = 0; i < elems.length; i++) {
  18. (function (lockedInIndex) {
  19. elems[i].addEventListener(‘click‘, function (e) {
  20. e.preventDefault();
  21. alert(‘I am link #‘ + lockedInIndex);
  22. }, ‘false‘);
  23. })(i);
  24. }
  25. // 你也可以像下面这样应用,在处理函数那里使用自执行函数表达式
  26. // 而不是在addEventListener外部
  27. // 但是相对来说,上面的代码更具可读性
  28. var elems = document.getElementsByTagName(‘a‘);
  29. for (var i = 0; i < elems.length; i++) {
  30. elems[i].addEventListener(‘click‘, (function (lockedInIndex) {
  31. return function (e) {
  32. e.preventDefault();
  33. alert(‘I am link #‘ + lockedInIndex);
  34. };
  35. })(i), ‘false‘);
  36. }

感谢@汤姆大叔 的《深入理解JavaScript系列》指导我学习!

复习JavaScript 5

上一篇:Symfony相关网站参考


下一篇:php面向对象的构造与构析方法