简介

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。

  1. function makeFunc() {
  2. var name = "Mozilla";
  3. function displayName() {
  4. alert(name);
  5. }
  6. return displayName;
  7. }
  8. var myFunc = makeFunc();
  9. myFunc();

原因在于,JavaScript中的函数会形成了闭包。 闭包是由函数以及声明该函数的词法环境组合而成的。该环境包含了这个闭包创建时作用域内的任何局部变量。在本例子中,myFunc 是执行 makeFunc 时创建的 displayName 函数实例的引用。displayName 的实例维持了一个对它的词法环境(变量 name 存在于其中)的引用。因此,当 myFunc 被调用时,变量 name 仍然可用,其值 Mozilla 就被传递到 alert中。

经典题目

  1. // 写一个函数,循环一个整数数组,延迟 3 秒打印这个数组中每个元素的索引。
  2. // 不正确实现
  3. const arr = [10, 12, 15, 21];
  4. for (var i = 0; i < arr.length; i++) {
  5. setTimeout(function() {
  6. console.log('The index of this number is: ' + i);
  7. }, 3000);
  8. }
  9. // 闭包解法
  10. const arr = [10, 12, 15, 21];
  11. for (var i = 0; i < arr.length; i++) {
  12. // 给每个函数传入变量 i 让其能访问正确的索引
  13. setTimeout(function(i_local) {
  14. return function() {
  15. console.log('The index of this number is: ' + i_local);
  16. }
  17. }(i), 3000);
  18. }
  19. // ES6解法
  20. const arr = [10, 12, 15, 21];
  21. for (let i = 0; i < arr.length; i++) {
  22. // 使用 ES6 中的 let 关键字,它会在函数调用时创建一个新的绑定
  23. // 了解更多:http://exploringjs.com/es6/ch_variables.html#sec_let-const-loop-heads
  24. setTimeout(function() {
  25. console.log('The index of this number is: ' + i);
  26. }, 3000);
  27. }



参考