让vs var:scope在for-loop中

时间:2016-08-06 06:28:19

标签: javascript for-loop ecmascript-6 closures

有人解释这个(var和let in for循环之间的行为差​​异)吗?

  1. 经典面试问题(闭幕):

    let a = [];
    for (var i=0; i<10; i++) {
        a[i] = function() {
          console.log(i,);
        }
    }
    a[0](); // 10
    a[1](); // 10
    
  2. 如果我们使用let:

    let a = [];
    for (let i=0; i<10; i++) {    // var => let
        a[i] = function() {
        console.log(i);
      }
    }
    
    a[0](); // 1
    a[1](); // 2
    
  3. 是的,我正常并且正如预期的那样使用'let'。 我想到的第一个想法是,不要支持关闭。但不,它支持。 (以下在Chrome上测试过):

    function bb() {
      let b = 1;
      return function() {
        console.log(b);
      }
    }
    bb()();    // 1, means a closure is created
    

    然后我的第二个解释是:当使用let in for循环时。对于每个循环,它会重复创建一个新的i。我在Chrome调试器中证明了这一点。

    问题是:

    如果在for循环中的每个循环中创建了i。它如何不断增加???为什么它不只是保持为0,因为我们声明它是否每次都被创建?

    for (let i=0; .......)
    

2 个答案:

答案 0 :(得分:4)

从您的示例中,每次迭代都会创建“词法声明”let i的环境。但是,for循环使用以前的环境来创建下一个环境。因此,当增量发生时,它从它停止的地方开始。否则,使用let声明i会产生无限循环(即i始终为<10)。

工作原理:

在for循环body evaluation中,'test'和'result'之后的步骤是CreatePerIterationEnvironment(perIterationBindings),它声明了一个新环境,并将所有绑定初始化为它们的上一个已知值:thisIterationEnv.InitializeBinding(bn, lastValue) 。完成后,新环境将设置为当前环境,并且“增量”步骤将开始。

定义:

  

InitializeBinding(N,V)设置环境记录中已存在但未初始化的绑定的值。字符串值N是绑定名称的文本。 V是绑定的值,是任何ECMAScript语言类型的值。

答案 1 :(得分:0)

第一个,错误的(意外的)结果只是因为闭包可以访问外部函数变量的更新值(最后闭包中的变量'i'是10);

第二个,使用let声明变量i以将其标记为block variable,这意味着闭包会立即获得i(如IIFE)。