【问题标题】:What is the temporal dead zone?什么是时间死区?
【发布时间】:2021-06-25 13:34:50
【问题描述】:

我听说在初始化之前访问letconst 值会导致ReferenceError,因为存在称为temporal dead zone的东西。

什么是时间死区,它与作用域和提升有什么关系,在什么情况下会遇到?

【问题讨论】:

标签: javascript ecmascript-6 constants let


【解决方案1】:

letconstvar 有两大区别:

  1. 他们是block scoped
  2. 在声明之前访问var 会得到undefined 的结果;在声明之前访问letconst 会抛出ReferenceError

console.log(aVar); // undefined
console.log(aLet); // Causes ReferenceError: Cannot access 'aLet' before initialization

var aVar = 1;
let aLet = 2;

从这些示例中可以看出,let 声明(和 const,其工作方式相同)可能不是 hoisted,因为 aLet 在被赋值之前似乎并不存在。

但情况并非如此 — letconst 被提升(如 varclassfunction),但在进入范围之间有一段时间并在无法访问的地方被声明。 这段时间是时间死区 (TDZ)

TDZ 在aLet声明而不是分配时结束:

// console.log(aLet) // Would throw ReferenceError

let aLet;

console.log(aLet); // undefined
aLet = 10;
console.log(aLet); // 10

这个例子表明let被提升了:

let x = "outer value";

(function() {
  // Start TDZ for x.
  console.log(x);
  let x = "inner value"; // Declaration ends TDZ for x.
}());

信用:Temporal Dead Zone (TDZ) demystified.

在内部范围内访问x 仍会导致ReferenceError。如果let 没有被提升,它将记录outer value

TDZ 是一件好事,因为它有助于突出错误——在声明之前访问一个值很少是有意的。

TDZ 也适用于默认函数参数。参数从左到右计算,每个参数都在 TDZ 中,直到它被分配:

// b is in TDZ until its value is assigned.
function testDefaults(a = b, b) { }

testDefaults(undefined, 1); // Throws ReferenceError because the evaluation of a reads b before it has been evaluated.

babel.js 转译器默认不启用 TDZ。打开“高合规”模式以在REPL 中使用它。提供 es6.spec.blockScoping 标志以将其与 CLI 一起使用或用作库。

推荐阅读:TDZ demystifiedES6 Let, Const and the “Temporal Dead Zone” (TDZ) in Depth

【讨论】:

  • @zeroflagL 很好的链接,谢谢。它还说:“ foo 不是未声明的,它是未初始化的”,该语言将有助于在上面的答案中澄清/纠正。块中的let foo 导致它被提升并在该块的顶部声明。 let foo 行导致它被初始化。并且foo = xyz 导致它被分配一个值。
  • 我认为这是一个很棒的帖子!但是,我的印象是“让”不受吊装的影响?我在 Mozilla 文档中发现了这一点:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 我并不是想成为一个脾气暴躁的人,我只是好奇,愿意澄清。
  • @jeows MDN 页面仍然显示它们没有被提升。如果您确实确定自己在说什么,则应该尝试对其进行编辑。我想我应该就此发表一个问题。
  • @joews IMO,您可以说它们已被吊起,但由于 TDZ 而在达到声明之前无法访问它们,或者您可以说它们没有被吊起但 TDZ 会导致任何引用它们以引发错误。实际上,这两种说法都同样正确。除了,我认为,您在抽象意义上使用“提升”一词,如“提升 = 每当引擎知道该变量的存在时”。这是为什么?另外,规范对此有何规定?
【解决方案2】:

吊装:
let,const,var都是吊装过程。
(这意味着它们会上升并在范围的顶部声明。)

初始化:

  • var也经过初始化过程,得到undefined的初始值。
  • 虽然let,const 没有抛出初始进程,所以它们的值仍然无法访问,尽管它们已经声明了。 什么把它们放在temporal dead zone

很快:

吊装过程:varletconst
初始化过程: var

【讨论】:

  • 我想还有一点很重要,letconst 是块作用域,var 是函数作用域
【解决方案3】:

在 let 和 const 变量的情况下,基本上,Temporal Dead Zone 是一个区域

“在你的变量被声明之前”,

即你不能访问这些变量的值,它会抛出一个错误。

例如

let sum = a + 5;        //---------
//some other code       //         | ------>  this is TDZ for variable a
                        //         |
console.log(sum)        //---------
let a = 5;

上面的代码报错

当我们使用 var 变量 'a' 时,相同的代码不会出错,

例如

var sum = a;                            
console.log(sum)     //prints undefined
var a = 5;

【讨论】:

  • 控制台日志在第二个示例中生成“NaN”(添加undefined5 的结果)。 var a声明被提升,初始化代码a设置为5没有。
  • 是的,对,a 没有任何初始化就被提升了。所以 a 将是未定义的。
  • 引用的第一个例子不正确,请更正或删除。
猜你喜欢
  • 2022-12-05
相关资源
最近更新 更多