首页 文章

是否在ES6中使用let或const声明变量?

提问于
浏览
205

我已经玩了ES6一段时间了,我注意到虽然用 var 声明的变量按预期被提升了......

console.log(typeof name); // undefined
var name = "John";

...用 letconst 声明的变量似乎在提升方面存在一些问题:

console.log(typeof name); // ReferenceError
let name = "John";

console.log(typeof name); // ReferenceError
const name = "John";

这是否意味着用 letconst 声明的变量不会被挂起?这是怎么回事? letconst 在这件事上有什么区别吗?

3 回答

  • 280

    @thefourtheye在声明这些变量 cannot be accessed 之前是正确的 . 但是,它有点复杂 .

    是否使用let或const声明变量?这是怎么回事?

    JavaScript中的 All declarationsvarletconstfunctionfunction*classare "hoisted" . 这意味着如果在范围中声明了名称,则在该范围内,标识符将始终引用该特定变量:

    x = "global";
    // function scope:
    (function() {
        x; // not "global"
    
        var/let/… x;
    }());
    // block scope (not for `var`s):
    {
        x; // not "global"
    
        let/const/… x;
    }
    

    对于函数和块作用域1都是如此 .

    var / function / function* 声明和 let / const / class 声明之间的区别是 initialisation .
    当在作用域顶部创建绑定时,前者使用 undefined 或(生成器)函数进行初始化 . 然而,词汇声明的变量仍然是 uninitialised . 这意味着当您尝试访问它时会抛出 ReferenceError 异常 . 它只会在评估 let / const / class 语句时被初始化,在此之前(上面)被称为时间死区的所有内容 .

    x = y = "global";
    (function() {
        x; // undefined
        y; // Reference error: y is not defined
    
        var x = "local";
        let y = "local";
    }());
    

    请注意, let y; 语句使用 undefined 初始化变量,就像 let y = undefined; 一样 .

    时间死区不是语法位置,而是变量(范围)创建和初始化之间的时间 . 只要不执行该代码(例如函数体或简单的死代码),引用声明上方代码中的变量并不是错误,如果在初始化之前访问变量,即使访问它也会引发异常代码在声明之下(例如,在过早调用的提升函数声明中) .

    在这件事上,let和const之间有什么区别吗?

    不,就提升而言,它们的工作原理相同 . 它们之间的唯一区别是 const ant必须且只能在声明的初始化部分中分配( const one = 1;const one; 和后来的重新分配,如 one = 2 都无效) .

    1:var声明当然只在函数级别上工作

  • 69

    引用ECMAScript 6(ECMAScript 2015)规范,let and const declarations部分,

    变量是在实例化包含词法环境时创建的,但在评估变量的LexicalBinding之前可能无法以任何方式访问它们 .

    所以,回答你的问题,是的, letconst hoist但是在运行时评估实际声明之前你无法访问它们 .

  • 17

    ES6 引入 Let 变量,其中包含 block level scoping . 直到 ES5 ,我们没有 block level scoping ,因此在块内声明的变量总是 hoisted 到函数级别作用域 .

    基本上 Scope 指的是程序中变量可见的位置,它决定了允许使用已声明的变量的位置 . 在 ES5 中我们有 global scope,function scope and try/catch scopeES6 我们也通过使用Let来获得块级别的范围 .

    • 使用 var 关键字定义变量时,会定义's known the entire function from the moment it' .

    • 使用 let 语句定义变量时,它定义了's only known in the block it' .

    function doSomething(arr){
         //i is known here but undefined
         //j is not known here
    
         console.log(i);
         console.log(j);
    
         for(var i=0; i<arr.length; i++){
             //i is known here
         }
    
         //i is known here
         //j is not known here
    
         console.log(i);
         console.log(j);
    
         for(let j=0; j<arr.length; j++){
             //j is known here
         }
    
         //i is known here
         //j is not known here
    
         console.log(i);
         console.log(j);
     }
    
     doSomething(["Thalaivar", "Vinoth", "Kabali", "Dinesh"]);
    

    如果运行代码,您可以看到变量 j 仅在 loop 中已知,而不是之前和之后 . 然而,我们的变量 ientire function 中从定义之后就已知 .

    使用let还有另一个很大的优势 creates a new lexical environment and also binds fresh value rather than keeping an old reference.

    for(var i=1; i<6; i++){
       setTimeout(function(){
          console.log(i);
       },1000)
    }
    
    for(let i=1; i<6; i++){
       setTimeout(function(){
          console.log(i);
       },1000)
    }
    

    第一个 for 循环始终打印最后一个值, let 它创建一个新范围并绑定新值,打印我们 1, 2, 3, 4, 5 .

    来到 constants ,它的工作基本上就像 let ,唯一的区别是它们的值无法改变 . 在常量 mutation is allowed but reassignment is not allowed.

    const foo = {};
    foo.bar = 42;
    console.log(foo.bar); //works
    
    const name = []
    name.push("Vinoth");
    console.log(name); //works
    
    const age = 100;
    age = 20; //Throws Uncaught TypeError: Assignment to constant variable.
    
    console.log(age);
    

    如果常量引用 object ,它将始终引用 object ,但 object 本身可以更改(如果是变) . 如果你想拥有一个不可变的 object ,你可以使用 Object.freeze([])

相关问题