为什么此代码不会导致 ReferenceError?

Why does this code not result in a ReferenceError?

if(true) {
  tmp = 'abc';
  console.log(tmp);//which should throw referenceError but not

  let tmp;
  console.log(tmp);

  tmp = 123;
  console.log(tmp);
}

此代码导致

abc
undefined
123

为什么第一个 console.log(tmp) 没有抛出错误?


why it should throw a referenceError

In ECMAScript 2015, let will hoist the variable to the top of the block. However, referencing the variable in the block before the variable declaration results in a ReferenceError. The variable is in a "temporal dead zone" from the start of the block until the declaration is processed.


我认为问题是bable设置。
所以,也许这是 babel 的一个错误? https://github.com/babel/babel.github.io/issues/826

不,它不应该引发引用错误。

当你赋值给它时,变量被隐式声明(在全局范围内)。

然后,稍后,您声明一个 new 具有相同名称但范围更小的变量。新变量未提升,因为它是使用 let.

声明的

我无法给出更准确的答案,因为你没有解释为什么你认为你应该得到一个引用错误。

声明

tmp = 'abc';

不优雅但在正常模式下仍然可以( 除了 let 关键字在严格模式 之外是不允许的。它只会创建全局变量。但是,代码不正确,只有当您在 "strict mode" 中执行此代码时才会抛出错误。在这种模式下,您必须使用以下关键字之一声明所有变量:

  • 变量
  • 常数

'use strict'
if(true) {
  tmp = 'abc';
  console.log(tmp);//which should throw referenceError and now it does
                  
  let tmp;
  console.log(tmp);

  tmp = 123;
  console.log(tmp);
}

你是对的,在 ES6 中这确实会抛出异常。它不适合您的原因有两个:

  • node.js 已经实现 let - 但它只能在严格模式下正常工作。你应该使用它。
  • babel 似乎默认不会转译 TDZ,因为它非常复杂并且会导致冗长的代码。但是,您可以使用 es6.blockScopingTDZ/es6.spec.blockScoping 选项启用它(但我不确定这是否仅在 Babel 5 中有效以及在 Babel 6 中发生了什么)。