【问题标题】:What is the temporal dead zone?什么是暂时死区?
【发布时间】:2022-12-05 06:53:05
【问题描述】:

我听说在初始化之前访问 letconst 值可能会导致 ReferenceError 因为一些叫做时间死区.

什么是暂时性死区,它与范围和提升有什么关系,在什么情况下会遇到?

【问题讨论】:

标签: 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).

    aLet 时 TDZ 结束宣布, 而不是分配:

    // 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】:

吊装:
letconstvar 都是 get hoisted 进程。
(什么意思是他们向上并在范围的顶部声明。)

初始化:

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

所以很快:

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

【讨论】:

  • 我想提到 letconst 是块作用域,var 是函数作用域也很重要
【解决方案3】:

在 let 和 const 变量的情况下,基本上,时间死区是一个区域

“在声明变量之前”,

也就是说,如果您无法访问这些变量的值,则会引发错误。

前任。

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

上面的代码给出了一个错误

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

前任。

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

【讨论】:

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