经典面试题:var、 let、 const 之间的区别

题目:var let const 之间的区别

题解:

三个关键词都是用来声明变量的,其中var在ECMAScript所有版本中都可以使用,而constlet只能在ECMAScript6及更晚的版本中使用。

var vs let

  • 声明作用域

    使用var操作符声明的变量作用域是包含该变量的函数,该变量将在函数退出时被销毁。
    使用let操作符声明的变量作用域是包含该变量的块作用域,块作用域直观理解就是{}包裹的代码块。函数作用域也可以理解为一个块作用域,因此适用于var的作用域限制也同样适用于let

  • 声明提升

    使用var声明的变量会自动提升到函数作用域顶部:

    function foo() {
        console.log(age);
        var age = 26;
    }
    foo(); // undefined
    

    以上代码等同于:

    function foo() {
        var age;
        console.log(age);
        age = 26;
    }
    foo(); // undefined
    

    let声明的变量却没有这个“特权”,不会被提升到作用域顶部。JavaScript引擎在解析代码时会察觉本作用域内有let,在let声明变量执行之前的这段过程被称为“暂时性死区”,凡是在此阶段引用let声明的变量都会抛出ReferenceError

  • 变量重复声明

    var可以在作用域内重复声明,但let不允许同一个块作用域中出现重复声明,即使是用var声明的变量。一个变量名只允许我let独享,就是这么霸道:

    var obj0;
    var obj0; // 不会报错
    var obj1;
    let obj1; // SyntaxError: Identifier 'obj1' has already been declared
    let obj2;
    var obj2; // SyntaxError: Identifier 'obj1' has already been declared
    
  • 全局变量

    let在全局作用域中声明的变量不会像var声明的变量一样成为window对象的属性,不过同样也会和页面共存亡。

const vs let

两个都是在ES6版本出生的,constlet基本相同,唯一一个重要区别是const声明变量时必须同时初始化,并可不能修改。注意const如果声明的是一个对象,那么不能更改的是对该对象的引用,也就是不能重新指向其他变量,但是修改对象内部属性const是管不着的。

const obj1 = {a: 1};
obj1.b = 2; // 不会报错
obj1 = {a: 1, b:2}; // TypeError: Assignment to constant variable.

衍生题

问:以下代码会输出什么?

for (var i = 0; i < 5; i++) {
    setTimeout(() => console.log(i), 0)
}

答:会打印出5个5,因为退出循环时变量i已经被赋值为5,执行超时逻辑时,每个回调函数都是指向那个已经变成5的i变量。

问:那么如何更改上面的代码使其挨个输出0,1,2,3,4呢?

答:只需把i的声明操作符改成let

for (let i = 0; i < 5; i++) {
    setTimeout(() => console.log(i), 0)
}

问:那么let是怎么做到的呢?

答:来看看babel将上一段代码转成es5后的样子:

es5.png

重新定义了一个函数,在循环中调用该函数,并将i作为函数参数传进去,这样,setTimeout执行时打印的是该函数的实参,而不再是for循环里变量i。

你可能感兴趣的:(经典面试题:var、 let、 const 之间的区别)