【前端进阶】let、const、var 的区别有哪些?

背景:由高级前端工程师@刘小夕 在github上发起的一个开源项目:每个工作日发布一个前端相关的问题,每周进行一次汇总。我觉得很不错,也参与其中,如果你也感兴趣,可以一起参与,项目地址:https://github.com/YvetteLau/Step-By-Step

let

let是ES6新增的命令,用来声明变量。它的用法和var类似,但是它所声明的变量,只在let命令所在的代码块内有效,即只在它所在的块级作用域内有效。

{
    let a = 1;
    var b = 2;
}

console.log(a); // ReferenceError: a is not defined
console.log(b); // 2

不存在变量提升

var命令会存在变量提升现象,即变量可以在声明之前使用,值为undefined

let命令,一定要变量先声明后,才可以使用,否则报错。

console.log(a);  // undefined
var a = 10;

console.log(b);  // ReferenceError: b is not defined
let b = 20;

var在全局作用域下声明的变量会挂载在window上,let不会。

var a = 10;
let b = 20;
console.log(window.a); // 10
console.log(window.b) // undefined

暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”了这个区域,不再受外部的影响。

var a = 10;

if (true) {
    console.log(a);  // ReferenceError: a is not defined
    let a;
}

上面代码中,虽然存在全局变量a,但是在块级作用域内又用let命令声明了一个局部变量a,导致a跟这个块级作用域绑定了,所以let命令在声明变量之前是无法使用的。

不允许重复声明

let命令不允许在相同作用域内,重复声明同一个变量。

function f1() {
    let a = 10;
    var a = 20;
}

f1();
// 报错:SyntaxError: Identifier 'a' has already been declared

因此,也不能在函数内部重复声明参数。

function f2(arg) {
    let arg;
}

f2();
// 报错:SyntaxError: Identifier 'arg' has already been declared
function f2(arg) {
    {
        let arg;
    }
}

f2(); // 不报错

const

const也是ES6新增的命令,用来声明一个只读的常量,一旦声明,常量的值就不能被改变。

const PI = 3.1415;
PI; // 3.1415;
PI = 3;
// TypeError: Assignment to constant variable.

const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。

const a;
// SyntaxError: Missing initializer in const declaration

const的作用域与let相同:只在声明所在的块级作用域内有效。

const命令声明的常量也不存在变量提升,同样存在暂时性死区,只能在声明的位置后才能使用。

const声明的常量也与let一样不可重复声明。

const声明的常量跟let一样不会挂载在window

本质

const实际上保证的,并不是变量的值不可改动,而是变量所指向的那个内存地址所保存的数据不得改动。

对于简单类型的数据(数值、字符串、布尔值),值就保存在变量所指向的那个地址,因此等同于常量。

但对于复杂类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

const obj = {};
// 为obj添加一个属性,可以成功
obj.prop = 10;
obj.prop; // 10

// 将obj指向另一个对象就会报错
obj = {}; // Assignment to constant variable.

看下数组的例子:

const arr = [];
arr.push(1);  // 可以执行
arr; // [1]
// 把另外一个数组赋值给它就会报错
arr = [2,3]; // Assignment to constant variable.

总结

  • var声明的变量存在变量提升;
  • letconst声明的变量/常量不存在变量提升,不可以在声明之前使用,存在暂时性死区;
  • letconst不可以重复声明同一个变量/常量;
  • var在全局作用域下声明的变量会挂载在window上,letconst不会;
  • const声明的常量必须立即初始化且不能再被重新赋值;