如果使用相同名称的 'let' 两次(在 for 循环中),Babel 会重新声明函数参数

Babel redeclares function parameter if 'let' with the same name is used twice (in a for loop)

当我做这样(愚蠢的)事情时:

function doBar(bar) {
  for (let bar = 0; bar < 10; bar++) {
    let bar = true;
  }
}

Babel 生成这个:

function doBar(bar) {
  for (var bar = 0; bar < 10; bar++) {
    var _bar = true;
  }
  // bar is redeclared and has the value 10
}

我使用了带有 es2015 选项的 babeljs.io 工具。

请检查babeljs.io example


问题:它应该那样工作吗?

为什么生成的javascript不是这样的:

for (var _bar = 0; _bar < 10; _bar++) {
  var _bar = true;
}

for (var _bar = 0; _bar < 10; _bar++) {
  var _bar2 = true;
}


编辑:babeljs.io example 添加了一些控制台输出以显示如何重新声明函数 variabel。

letvar不一样。

let 在块范围内定义一个变量,例如您的 for 循环。 var 在全局或函数范围内定义一个变量。

因此,当您获得代码时:

function doBar(bar) {
  for (let bar = 0; bar < 10; bar++) {
    let bar = true;
  }
}

外部 "bar" 是为函数 doBar 定义的,而内部 "bar" 是为 for(){} 块范围定义的。

没有"redeclaring"。当 bable 转换它时,你会得到预期的行为,外部 "bar" 在函数内,当你退出 for 循环时它保持在最大值,内部 _bar 是一个完全不同的变量。

因为它们都被转换为 var 而不是 let 并且被提升了。

评论相关例子:
如果你有这种类型的代码:

function doBar(bar) {
  for (let bar = 0; bar < 10; bar++) {
    let bar = true;
  }
}

首先,这在语义上是错误的。这包含重新声明。这两个 bar 变量都在 for 块的范围内声明。但是你不会抛出任何错误,没有 babel 也是如此。由于变量 bar 的重新声明发生在 for 的范围块内,for 的 "parameter" bar 被覆盖并且块本身无法访问,但是似乎循环仍然正常 运行s,正确的次数。

因为这个 "silent error" 和块中重新声明的变量 let bar ,babel 不认为这两个变量是相同的,它们是不同的。 错误的原因 在于通过在块内重新声明变量,您有效地使块自己的变量无法访问任何东西,无论是块还是块外.

现在从 babel 的角度来看,循环应该 运行,循环的参数在 for 括号内外的任何地方都不可访问,因此这是一个孤立的 "scope" for bar 在 for.

let 不同,var 可以在不引发错误的情况下重新声明,但是这种静默重新声明在两种情况下都不会引发错误,其中一个应该已经上升并且这就是导致问题的原因。

解决方案是编写正确的代码,但你是 100% 正确的,这不是正确的行为,但是,非 bable 代码的常规 javascript 解释器也不是,因为它应该抛出一个错误,你不能 expect/blame babel 以错误的方式解释错误的代码。

Babel 只是部分正确。

When I do something (stupid) like this:

function doBar(bar) {
  for (let bar = 0; bar < 10; bar++) {
    let bar = true;
  }
}
doBar("BAR");

…那么你可能没想到这里有 三个不同的变量 命名为 bar 在三个不同的范围内。

但这是真的:

  1. 参数声明的function-scope(var-like)bar
  2. fooheader中的let声明引入的loop-scopedbar,其special scoping rules
  3. block-scopedbarlet声明在形成循环的块中引入body语句

它们都有独立的值(1:字符串,2:整数,3:布尔值)并且互不影响。这一点很明显,因为没有语法错误被抛出 - 否则任何 let 重新定义一个 function-scoped 变量(参数,var 声明)或一个 let 在与其自身相同的范围内会抛出早期错误。

Babel generates this […]. Should it work that way?

没有。正如你在doFoo中所看到的,Babel实际上认识到变量1和2是不同的。它还确实认识到 2 和 3 是不同的。但是一旦你引入所有三个,它就会混淆 1 和 2,将它们转换为相同的标识符。