18 Jan 2017 10:59 +0000

闭包是 JavaScript 新手最容易遇到的一个问题, 之所以说新手, 是因为闭包在 JavaScript 中出现得非常频繁, 是理解 JavaScript 这门语言必须掌握的概念.

最经典的闭包案例:

const arr = ['a', 'b', 'c', 'd']; // 以下所有代码都用该数据
let i; 

for (i = 0; i < arr.length; i++) {
  setTimeout(() => {
    console.log('Index: ' + i);
  }, 200);
}

显然, 代码作者的预期结果是:

Index: 0
Index: 1
Index: 2
Index: 3

但是很可惜, 以上代码将在 200ms 后输出 4 次 'Index: 4', 因为在setTimeout()中形成了闭包, 在该闭包中访问了外部变量i, 但是i在 200ms 后已经变成 4, 因此造成所有的输出都是 4.

解决方案:

传递中间变量
let i; 

for (i = 0; i < arr.length; i++) {
  // 通过传递变量 i, 使每个函数都获取到正确的索引
  setTimeout(((i_local) => {
    return () => {
      console.log('Index: ' + i_local);
    }
  })(i), 1000);
}

如果你对 ES6 的特性或立即调用不熟悉, 以上代码等价于:

let i; 

function temp(i) {
  return function () {
    console.log('Index: ' + i);
  }
}

for (i = 0; i < arr.length; i++) {
  // 通过传递变量 i, 使每个函数都获取到正确的索引
  setTimeout(temp(i), 1000);
}
利用 let 的特性
for (let i = 0; i < arr.length; i++) {
  setTimeout(() => {
    console.log('Index: ' + i);
  }, 1000);
}

let 会在每次调用时生成新的引用, 即每次调用时 let 是不同的, 所以最后输出不会全是 4.


Loading comments...