let关键字和闭包?

5

我正在学习ES6的新特性。我对let关键字有一个问题,并且涉及到以下代码:

for (let i = 0; i < 45; i++) {
    var div = document.createElement('div');
    div.onclick = function() {
        alert("you clicked on a box #" + i);
    };
    document.getElementsByTagName('section')[0].appendChild(div);
}

我对这段代码感到困惑。在每次循环开始时声明的div对象会发生什么?它是一个全新的、分离的对象吗?还是在每次循环中被覆盖了,如果是这样,它如何保持与let给出的i的连接关系?


onclick函数是一个闭包,它封闭了idiv与此无关。 - Bergi
3个回答

5

当我想更好地理解ES6代码时,我会将我的Javascript输入BabelJS REPL中。

当您的代码输入到REPL中时,输出结果为:

'use strict';

var _loop = function (i) {
  div = document.createElement('div');

  div.onclick = function () {
    alert("you clicked on a box #" + i);
  };

  document.getElementsByTagName('section')[0].appendChild(div);
};

for (var i = 0; i < 45; i++) {
  var div;

  _loop(i);
};

由于您使用了let来赋值i,其值仅在每个循环迭代的作用域内(或Babel示例中的函数)可用。要获取div变量的相同功能,您可以在循环体中赋值该变量。
for (let div, i = 0; i < 45; i++) {
  div = document.createElement('div');
  ...
}

最后,关于闭包和保留变量 i,你只需要再进一步创建一个闭包来维护每个 div 的当前 i 值。
// Create a function to hold on to a specific number
function createOnClick(index) {
  return function() {
    alert("you clicked on a box #", index);
  };
};

// Assign the function to the element's action 
div.onClick = createOnClick(i);

没有函数工厂,onClick的值将总是获得最大的i值44。这是因为函数是在整个循环迭代后运行的,而i已经停止在i < 45

2
<div>是每次迭代中的全新对象,但它并没有被包含在i的块级作用域中。

附加到div的函数表达式也是一个全新的对象,但该对象正在闭合i

0
在每次迭代中,div 都是一个全新的元素对象。leti 定义为仅在 foreach 循环内部可访问 ("使用"let"和"var"声明变量有什么区别?)。
一旦将 div 元素附加到 "section" 元素中,并且 for 循环开始新的迭代,您将通过用新的元素覆盖它来失去对最近附加的 div 的引用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接