ES6规范新增了let、const两种变量声明方式,项目中也经常要用到,今天借着温习ES6语法,来总结let 、const、var的区别。
变量提升
来看下面三段代码
1 | console.log(a); // undefined |
1 | console.log(b); // Uncaught ReferenceError: b is not defined |
1 | console.log(c); // Uncaught ReferenceError: c is not defined |
用var声明的变量,会在其作用域中发生变量提升,js默认给变量一个undefined值。
但是,在ES6中使用let/const声明的变量,不存在变量提升过程。也就是说,在使用let/const声明的变量,声明前访问它,都会报错。
暂时性死区
代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
1 | let a = 'global'; |
上述代码中,if代码块里,在let声明变量a之前,都是a的”暂时性死区”,在该范围内访问a都会报错。
由此可见,块级作用域内存在let声明的话,它所声明的变量就绑定在这个块级作用域,不再受外部影响。
重复声明
let 和 const 命令声明的变量不允许重复声明;而使用var声明变量,可以多次重复声明一个同名变量,但最终变量的值为最后一次声明赋值的结果。
1 | var a = 10; |
let与const在相同作用域声明重复的变量会报错
1 | let a = 10; |
var和let同时声明同一个变量,也是报同样的错误
1 | let b = 10; |
或先var,再let
1 | var c = 10; |
作用域
这里就涉及到一个最经典的问题:
1 | for (var i = 0; i < 5; i++) { |
这个问题的解决可以使用闭包等,ES6的let为这个问题提供了新的解决方法:
1 | for (let i = 0; i < 5; i++) { |
使用let声明的变量仅在块级作用域内有效。 i在循环体内的局部作用域,不受外界影响。
在ES6之前,都是用var来声明变量,而且JS只有函数作用域和全局作用域,没有块级作用域,所以花括号{}限定不了var声明变量的访问范围。
1 | { |
let、const声明的全局变量不会作为window对象的一个属性
使用var声明的全局变量,会被JS自动添加在全局对象window上,但let和const不会
1 | let a = 10; |
const声明常量
由于const用来声明常量,一旦声明,就必须立即初始化,而且声明之后值不能改变。
1 | const a = 10; |
常量的值不变,实际上是指常量指向的那个内存地址中所保存的数据不可更改。
对于基本数据类型(数值,字符串、布尔值),他们本身具体的值就保存在常量所指向对应的栈内存地址中,所以修改值就等于修改栈内存地址,这显然不允许会报错。
但是,如果一个常量的值是一个引用类型值,那么常量所指向的内存地址(堆内存)中实际保存的是指向该引用类型值的一个指针(也就是引用类型值在内存中的地址)。所以const只能保证该引用类型地址不变,但该地址中的具体数据是可以变化的。
如下代码:
1 | const obj = {}; |
如何正确使用
在开发的时候,声明变量我们应该少使用var,避免产生不必要的全局变量。当需要改变变量的值时声明用let,对于需要写保护的变量或定义常量使用const。