【问题标题】:Why does this code not result in a ReferenceError?为什么此代码不会导致 ReferenceError?
【发布时间】:2023-04-02 03:40:02
【问题描述】:
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

在 ECMAScript 2015 中,让我们将变量提升到块的顶部。但是,在变量声明之前引用块中的变量会导致 ReferenceError。从块开始到处理声明,该变量处于“临时死区”中。


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

【问题讨论】:

  • 当你定义它时为什么会抛出错误tmp = 'abc';
  • 您对tmp = 'abc' 的原始用法是隐式声明一个变量。
  • 请向我们展示您的 babel 设置。这肯定会引发错误,尽管如果您在松散模式下编译可能不会。
  • 可能是 babel 的问题?我在 chrome 中运行此代码,它可以工作
  • @Bergi 这里是我的 .babelrc 文件内容{ "presets":[ "babel-preset-es2015" ], "plugins": [ "babel-plugin-transform-es2015-destructuring", "babel-plugin-transform-es2015-modules-commonjs" ] }

标签: javascript ecmascript-6 babel-node


【解决方案1】:

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

变量在赋值时被隐式声明(在全局范围内)。

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

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

【讨论】:

  • let tmp; 在块语句中声明它,然后tmp = 'abc'; 尝试在实际评估 let tmp; 行之前分配给它,这是 ES6 中@987654325 的错误条件@.
【解决方案2】:

声明

tmp = 'abc';

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

  • 变量
  • 常量

'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);
}

【讨论】:

  • 我认为这是 babel 的错误。我在 chrome 中运行此代码时没有“使用严格”,它会引发 ReferenceError。当我在 babel 的“使用严格”中运行此代码时,它仍然显示相同的结果
  • 但是如果你可以使用 let 关键字,这意味着你处于“严格模式”,你应该看到这个错误,我们可以在上面的 sn-p 中看到它。巴别虫?
  • “正常模式”是指草率模式(非严格)?请注意,在纯 ES6 中它仍然是一个错误,只有实现(V8)因为向后兼容而允许它。
  • 是的 - 意味着草率模式。这里有趣的问题是这段代码不应该在任何模式下运行。在草率的情况下,它应该抛出:SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode。在严格模式下,它应该抛出 ReferenceError: tmp is not defined
【解决方案3】:

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

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

【讨论】:

  • 对不起,TDZ是什么?
  • @Runjuu: temporal dead zone - 尽管是声明的变量,但导致访问抛出的东西。
  • Babel 6 的 TDZ 仍然有很多问题,所以我认为没有多少人使用它。
  • @loganfsmyth:我对 babel 及其版本了解不多。你是说它在 Babel 5 中确实有效,但在 6 中无效?您是否有一些链接(可能是跟踪错误报告)来支持“仍然有很多错误”?我曾尝试在phabricator.babeljs.io 进行搜索,但似乎无法按版本过滤或按日期排序。如果您有相关内容,也可以直接编辑我的答案,或发布您自己的:-)
  • 至于Babel 6中的TDZ,这个案子好像没有处理。我猜想 es6.spec.blockScoping 已被 babeljs.io/docs/plugins/transform-es2015-block-scoping 插件取代,但它只处理块作用域。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多