无法理解为什么让变量名抛出错误

时间:2019-04-20 11:34:33

标签: javascript

此示例摘自mdn,并且由于

而引发错误
  

n.a的指令let n已在的私有范围内   for循环的块,因此将标识符“ n.a”解析为   位于对象第一部分的'n'对象的属性'a'   指令本身(“ let n”),该指令仍处于时间盲区   因为它的声明语句尚未到达并终止。

function go(n) {
  for (let n of n.a) {
    console.log(n);
  }
}

go({
  a: [1, 2, 3]
});

现在,我将变量名从n更改为k,它可以工作了。但是根据mdnlet k仍将处于时间盲区。 那怎么不抛出错误而是记录值呢?

function go(n) {
  for (let k of n.a) {
    console.log(k);
  }
}

go({
  a: [1, 2, 3]
});

4 个答案:

答案 0 :(得分:1)

  

但是根据mdn let k仍将处于暂时的盲区。

否,到您在代码(console.log(k))中使用它时,它已经使用该循环的迭代值进行了初始化。它不在TDZ中。

let n版本的TDZ问题在这里:

for (let n of n.a) {
// -----------^

那时,用n声明的let遮盖了n参数。它是保留的,并且在TDZ中,但是代码正在尝试在n中使用它(而不是of n.a参数)。对于您的k版本来说,这不是问题,因为您在那里没有引用k

答案 1 :(得分:1)

for (let n of n.a) {
//         ^^^^^^

该语句的时间盲区是带下划线的of n.a部分。由于它包含对n(由let n声明的变量)的引用,因此是错误的。

for (let k of n.a) {
//         ^^^^^^

在此示例中,时间盲区仍然由n.a组成,但是我们现在声明一个不同的变量k。由于死区中的表达式不使用k,所以很好。

答案 2 :(得分:1)

在第一种情况下,这是一个ReferenceError,因为如果在of的两边都使用了变量名,则规范希望避免混淆。从理论上讲,即使第一个版本也可以工作,然后这样做:

 for(let n of n.a) { /*body*/ }

可以执行为:

 const iterator = n.a[Symbol.iterator](); // the iterator is initialized in the parent scope
 let done = true;
 while(!done) {
   let n;
   ({ value: n, done } = iterator.next()); // "n" is initialized in the local loop scope.
   /* body */
 }

但是,如果右侧的n.a不引用左侧的n,那会造成混乱,因此规范的作者添加了另一个作用域,以防止变量循环在迭代器中使用:所有局部变量也都在另一个作用域中声明,该作用域仅用于初始化迭代器:

 { // another local scope (named TDZ in the spec)
   const iterator = n.a[Symbol.iterator](); // "n" cannot be used here, as it was not yet initialized
   let done = false;

   let n; // this is just to prevent "n" from being used in the line above

    while(!done) {
       let n;
       ({ value: n, done } = iterator.next());
    }
 }

规范的相关部分:

  

13.7.5.12运行时语义:ForIn / OfHeadEvaluation

     

[...]

 b. Let TDZ be NewDeclarativeEnvironment(oldEnv).

 [...]

 d. For each string name in TDZnames, do

   i. Perform ! TDZEnvRec.CreateMutableBinding(name, false).

 e. Set the running execution context's LexicalEnvironment to TDZ.

3. Let exprRef be the result of evaluating expr

在这种情况下, expr n.a,而 TDZnames 包含n

答案 3 :(得分:0)

“ n在TDZ中”是指循环声明中的第二个n,“ let n of n .a ”。使用“ for(让k为n.a)” 不存在此问题:引用 k 的唯一时间是循环内。