Javascript ES6中let吊装的目的是什么?

Javascript ES6中let吊装的目的是什么?,javascript,ecmascript-6,Javascript,Ecmascript 6,我知道let将被提升到块的顶部,但在初始化之前访问它将抛出ReferenceError,因为它处于暂时死区 例如: console.log(x); // Will throw Reference Error let x = 'some value'; 但这样的代码片段将不会出错: foo(); // alerts foo; function foo(){ // foo will be hoisted alert("foo"); } 我的问题 let被提升到顶部时会在访问时抛

我知道
let
将被提升到块的顶部,但在初始化之前访问它将抛出
ReferenceError
,因为它处于
暂时死区

例如:

console.log(x);   // Will throw Reference Error
let x = 'some value';
但这样的代码片段将不会出错:

foo(); // alerts foo;
function foo(){    // foo will be hoisted 
  alert("foo");
} 
我的问题

let
被提升到顶部时会在访问时抛出错误,其目的是什么?同样,var也会受到TDZ的影响,我知道它什么时候会抛出未定义的

变量是在其包含词法环境为 实例化,但在变量 已评估词典绑定。词汇表定义的变量 对于初始值设定项,将为其初始值设定项的 计算LexicalBinding时的AssignmentExpression,而不是在 变量被创建。如果let声明中的一个词典绑定 没有初始值设定项变量被赋予未定义的值 在对词典进行求值时

还包括:

let允许您声明在范围内受限于 用于其上的块、语句或表达式这与 var关键字,它全局定义变量,或局部定义变量 不考虑块范围的整个功能。


您也可以查看凯尔·辛普森的这篇文章:

您必须首先了解吊装。将代码声明初始化为块的顶部,请考虑以下示例

function getValue(condition) {
    if (condition) {
        var value = "blue";
        // other code
        return value;
    } else {
        // value exists here with a value of undefined
        return null;
    }
        // value exists here with a value of undefined
}
正如您所看到的,该值可以在else和function中访问。因为它直接在getValue(condition)函数之后声明

function getValue(condition) {
    if (condition) {
        let value = "blue";
        // other code
        return value;
    } else {
        // value doesn't exist here
        return null;
    }
    // value doesn't exist here
}
但是当我们使用时,让你看到不同。这些例子摘自我正在阅读的一本书,推荐你也去看

进一步澄清

用一种很好的方式解释了它,并提供了与该主题相关讨论的链接

解释这个问题的内容

为什么
let
存在暂时死区

  • 如果TDZ没有引起引用错误,并且您在变量声明之前(即在TDZ中)访问了变量,那么您(很可能)会错过一个编程错误。导致引用错误的TDZ可以帮助您捕获编程错误

  • 因此,您的下一个问题是-为什么要为
    let
    设置TDZ?为什么不在声明变量时启动
    let
    变量的作用域?答案是
    const
    。TDZ用于
    const
    和(差)
    let
    被TDZ卡住,只是为了更容易在
    let
    const
    之间切换


  • var也会受到TDZ的影响,我知道它什么时候会抛出未定义的 但这是因为TDZ吗

    否,
    var
    不受TDZ影响。它不会抛出任何错误。它只是
    未定义的
    ,除非另行设置。TDZ是一个ES6东西。

    A
    let
    变量未被提升。说一个
    let
    变量是“highed”在技术上是正确的,但我认为这个术语的使用是误导性的。描述语义的一种等效方法是,当您试图在其声明上方引用它时,会得到一个
    ReferenceError
    ,因为它还不存在;如果试图引用该块中任何地方都不存在的变量,也会得到同样的结果

    更多信息:

    C++和JavaScript都有块作用域,但在这一点上有所不同,所以我们可以通过了解它们的不同行为来理解这一点。考虑这个例子:

    #include <iostream>                                                         
    
    int main() {
        int x = 3;
    
        {
            std::cout << x << std::endl;
            int x = 4;
        }
    
        return 0;
    }
    
    在JavaScript中,通过“提升”第二个
    x
    ,解决了此问题,但使其在访问时抛出
    ReferenceError
    。据我所知,这种“提升”相当于将对
    x的引用视为由于歧义而产生的错误,这是应该的

    let
    被提升到顶部时会在访问时抛出错误,其目的是什么

    这样我们就可以有块范围,这是一个相当容易理解的概念,而不必有块等价物
    var
    highting,这是一个传统的bug和误解的来源

    考虑这一块的内部:

    {
        let a = 1;
        console.log(a);
        let b = 2;
        console.log(a, b);
        let c = 3;
        console.log(a, b, c);
    }
    
    设计师在这里有三个主要选择:

  • 具有块范围,但所有声明都挂到顶部并可访问(如
    var
    处于函数中);或
  • 没有块作用域,而是从每个
    let
    const
    类开始创建一个新作用域。;或
  • 有块作用域,有提升(或者我称之为“半提升”),其中声明被提升,但是它们声明的标识符在代码中到达之前是不可访问的
  • 选项1让我们面临着与
    var
    相同的bug。选项2对于人们来说要理解要复杂得多,对于JavaScript引擎来说要做的工作也更多(如果您需要,请参阅下面的详细信息)。选项3达到了最佳效果:块范围很容易理解和实现,TDZ可以防止由
    var
    引起的错误

    另外,
    var
    也会受到TDZ的影响,我知道它什么时候会抛出
    undefined
    ,但这是因为TDZ吗

    否,
    var
    声明没有TDZ<代码>未定义
    不会被抛出,它只是一个变量在声明时的值,但没有设置为任何其他值<代码>变量
    声明被提升到函数或全局环境的顶部,并在该范围内完全可访问,甚至在到达
    变量
    行之前


    这可能有助于理解JavaScript中如何处理标识符解析:

    规范用一种叫做a的东西来定义它,它包含关于varia的信息
    {
        let a = 1;
        console.log(a);
        let b = 2;
        console.log(a, b);
        let c = 3;
        console.log(a, b, c);
    }
    
    function example() {
        console.log("alpha");
        var a = 1;
        let b = 2;
        if (Math.random() < 0.5) {
            console.log("beta");
            let c = 3;
            var d = 4;
            console.log("gamma");
            let e = 5;
            console.log(a, b, c, d, e);
        }
    }