Skip to content

Latest commit

 

History

History
156 lines (110 loc) · 4.83 KB

ES6系列之let和const与var的区别.md

File metadata and controls

156 lines (110 loc) · 4.83 KB

ES6 系列之 let 和 const 与 var 的区别

ES6 规范新增了 let、const 两种变量声明方式,项目中也经常要用到,今天借着温习 ES6 语法,来总结 let 、const、var 的区别。

一、变量提升

来看下面三段代码

console.log(a) // undefined
var a = 2
console.log(b) // Uncaught ReferenceError: b is not defined
let b = 2
console.log(c) // Uncaught ReferenceError: c is not defined
const c = 2

用 var 声明的变量,会在其作用域中发生变量提升,js 默认给变量一个 undefined 值。

但是,在 ES6 中使用 let/const 声明的变量,不存在变量提升过程。也就是说,在使用 let/const 声明的变量,声明前访问它,都会报错。

二、暂时性死区

代码块内,使用 let 命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

let a = 'global'
if (true) {
  a = 'block' // Uncaught ReferenceError: a is not defined
  let a
}

上述代码中,if 代码块里,在 let 声明变量 a 之前,都是 a 的"暂时性死区",在该范围内访问 a 都会报错。 由此可见,块级作用域内存在 let 声明的话,它所声明的变量就绑定在这个块级作用域,不再受外部影响。

三、重复声明

let 和 const 命令声明的变量不允许重复声明;而使用 var 声明变量,可以多次重复声明一个同名变量,但最终变量的值为最后一次声明赋值的结果。

var a = 10
var a = 'abc'
var a = 'last value'
console.log(a) // last value

let 与 const 在相同作用域声明重复的变量会报错

let a = 10
let a = 20 // Uncaught SyntaxError: Identifier 'a' has already been declared

var 和 let 同时声明同一个变量,也是报同样的错误

let b = 10
var b = 20 // Uncaught SyntaxError: Identifier 'b' has already been declared

或先 var,再 let

var c = 10
let c = 20 // Uncaught SyntaxError: Identifier 'c' has already been declared

四、作用域

这里就涉及到一个最经典的问题:

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

这个问题的解决可以使用闭包等,ES6 的 let 为这个问题提供了新的解决方法:

for (let i = 0; i < 5; i++) {
  setTimeout(function () {
    console.log(i) // 0 1 2 3 4
  })
}

使用 let 声明的变量仅在块级作用域内有效。 i 在循环体内的局部作用域,不受外界影响。

在 ES6 之前,都是用 var 来声明变量,而且 JS 只有函数作用域和全局作用域,没有块级作用域,所以花括号{}限定不了 var 声明变量的访问范围。

{
  var a = 10
}
console.log(a) // 10

{
  let b = 9 // es6的let: b变量只在花括号内有效
}
console.log(b) // Uncaught ReferenceError: b is not defined

五、let、const 声明的全局变量不会作为 window 对象的一个属性

使用 var 声明的全局变量,会被 JS 自动添加在全局对象 window 上,但 let 和 const 不会

let a = 10
console.log(window.a) // undefined

var b = 20
console.log(window.b) // 20

const c = 30
console.log(window.c) // undefined

六、const 声明常量

由于 const 用来声明常量,一旦声明,就必须立即初始化,而且声明之后值不能改变。

const a = 10
a = 20 // Uncaught TypeError: Assignment to constant variable.

常量的值不变,实际上是指常量指向的那个内存地址中所保存的数据不可更改。

对于基本数据类型(数值,字符串、布尔值),他们本身具体的值就保存在常量所指向对应的栈内存地址中,所以修改值就等于修改栈内存地址,这显然不允许会报错。

但是,如果一个常量的值是一个引用类型值,那么常量所指向的内存地址(堆内存)中实际保存的是指向该引用类型值的一个指针(也就是引用类型值在内存中的地址)。所以 const 只能保证该引用类型地址不变,但该地址中的具体数据是可以变化的。

如下代码:

const obj = {}
obj.a = 3
console.log(obj) // {a: 3}

// 当obj指向了另一个对象,即obj中保存的地址发生了变化,即会报错
obj = {} // Uncaught TypeError: Assignment to constant variable.

如何正确使用

在开发的时候,声明变量我们应该少使用 var,避免产生不必要的全局变量。当需要改变变量的值时声明用 let,对于需要写保护的变量或定义常量使用 const。