在ES6中,使用let时for循环初始化表达式是否重新声明?

时间:2017-07-10 02:32:31

标签: javascript for-loop scope

我试图从MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

中澄清这一陈述背后的含义
  

上面的例子按预期工作,因为它的五个实例   (匿名)内部函数指的是五个不同的实例   变量i。

假设for循环初始化表达式使用let关键字。表达式是否在每次迭代时重新声明(即,有一个新范围)?例如,

var func;
for (let i = 0; i < 5; i++) {
  if (i == 1) {
    func = () => i
  }
  if (i == 4) {
    i = 100
  }
}
console.log(func()) // output is 1

func()的输出即使在{for循环结束时1也是i == 4。这似乎表明i中的func来自i == 1的范围,即使i在最后一次迭代中设置为100

将其与下面的i在for循环块之外声明的情况进行比较。

if (true) {
  var func;
  let i = 0
  for (i = 0; i < 5; i++) {
    if (i == 1) {
      func = () => i
    }
    if (i == 4) {
      i = 999
    }
  }
}
console.log(func()) // output is 999

在这种情况下,似乎有一个i实例在最后一次迭代中得到更新(但没有重新声明)。

那么,使用let是否会导致for循环创建一个新的块作用域,并为每次迭代创建一个init变量的新声明?

2 个答案:

答案 0 :(得分:0)

let声明的变量的作用域位于最近的块中。

  

http://exploringjs.com/es6/ch_core-features.html#sec_from-var-to-const

     

在ES6中,您还可以通过let和const声明变量。这些变量是块范围的,它们的范围是最里面的封闭块。 let大致是var。

的块范围版本

这意味着您的代码应该与此相同:

var func;
for (var i = 0; i < 5; i++) {
  (function (j) {
    if (j == 1) {
      func = () => j
    }
    if (j == 4) {
      j = 100
    }
  })(i);
}
console.log(func()) // output is 1

答案 1 :(得分:0)

13.7.4.9 of the ECMAScript spec节似乎表明zer00ne提到的是真的:

  • 为循环的每次迭代创建了一个新环境,
  • 以及在该环境中创建的i的新绑定
  • 并将其值设置为前一个绑定的值 迭代(而不是重新初始化)
  

iii让lastValue为lastIterationEnv.GetBindingValue(bn,true)。

     

诉执行thisIterationEnv.InitializeBinding(bn,lastValue)。

在循环内声明的函数将在特定于迭代的绑定上形成一个闭包 - 所以有效地,你将为循环的每次迭代获得一个不同的闭包。