let、const、var的区别?(面试题,超详细)

252 阅读4分钟

这道题是常见的面试题,但是想要答好,想要面试官眼前一亮,还是得答一些被平常人所不注意的知识点! ok,首先看到这个题,我脑子里想到的就是:

1.块级作用域:(必答)

块级作用域是: 由{}包括起来的部分

具有块级作用域: let和const;

不具有块级作用域: var

⭐补充: (亮点)

块级作用域解决了ES5中的两个问题:

① 内层变量可能覆盖外层变量

② 用来计数的循环变量泄露为全局变量

ok,我将用例子来说一下上面这两个问题!

<script>
        var x = 10;//外层变量x
        if (true) {
            var x = 20;//内层变量x
            console.log(x);
        }
        console.log(x);//这里本来应该是输出10,但是因为内层变量x的原因,所以外层变量x的值被内层变量x的值覆盖了
</script>

  //浏览器输出的结果是:20 20

如果把上面这段代码换成let来声明,会怎么样?

       let x = 10;
       if (true) {
           let x = 20;
           console.log(x);//输出20
       }
       console.log(x);//输出10,为什么不是20呢?因为let x = 20是在块里面,它不会覆盖外层let x = 10 的值,所以输出就是10 

ok,到此,解决了第一个问题“① 内层变量可能覆盖外层变量”!

接下来,解决第二个问题!

直接上代码解释:

        var a = [];
        for (var i = 0; i < 10; i++) {
            a[i] = function () {
                console.log(i);
            };
        }
        a[5]();//10
        a[6](); // 10

可能大家看到这个,一时懵了,为什么都是10。

别怕,我当时也是,但是认真分析一下,还是可以懂的。

解析: (认真理解下面这段解析)

上面代码中,变量ivar命令声明的,在全局范围内都有效,所以全局只有一个变量i

每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i

也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是 10。

ok,那如果我把上面对i的声明用let声明,那结果会是怎么样呢?

        var a = [];
        for (let i = 0; i < 10; i++) {
            a[i] = function () {
                console.log(i);
            };
        }
        a[5]();//5
        a[6]();//6

现在就不是10了,因为跟let是块级作用域有很大关系,那么同样解析一下:

上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是5、6。

你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

2.变量提升: (必答)

存在变量提升: var;

不存在变量提升: let和const;

即变量只能在声明之后使用,否则报错❌

// var 的情况

console.log(foo); // 输出undefined
var foo = 2;

//上面代码中,变量foo用var命令声明,会发生变量提升
//即脚本开始运行时,变量foo就已经存在了,但是没有值,所以会输出undefined。

//上面代码运行时,是下面这样子的:
var foo;
console.log(foo);



// let 的情况

console.log(bar); // 报错ReferenceError
let bar = 2;
//上面第17、18行代码中,变量bar用let声明,不会发生变量提升。
//这表示在声明它之前,变量bar是不存在的,这时如果用到它,就会抛出一个错误

3.给全局添加属性: (感觉不用非得答)

会将变量添加为全局对象的属性的是:var;

不会将变量添加为全局对象的属性的是:let和const;

浏览器的全局对象是window,node的全局对象是global,那var呢?var声明的变量为全局变量,且会将变量添加为全局对象的属性。

4.重复声明: (必答)

var 声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的变量;

let和const不允许重复声明变量

5.暂时性死区: (必答)

在使用let、const命令声明变量之前,该变量都是不可用的,这在语法上,称为“暂时性死区”。

使用var声明的变量不存在暂时性死区。

6.初始值设置: (必答)

在声明变量的时候,var 和 let 可以不用设置初始值,而const必须要设置初始值

7.指针指向: (必答)

let创建的变量是可以更改指针指向(也就是说可以重新赋值),var也可以,但是const不可以