ES6之let、const与var的区别
命令 | 作用域 | 是否变量提升 | 可否多次声明 |
---|---|---|---|
var | 函数作用域 | 是 | 可 |
let | 块级作用域 | 否(存在暂时性死区TDZ) | 不可 |
const | 块级作用域 | 否(存在暂时性死区TDZ) | 不可 |
let注意:
- 不存在变量提升(即没有预解析):
a.在代码块内,只要let定义变量,在定义前使用都会报错。(即TDZ 暂时性死区)
b.应先定义再使用。 - 在for(){}循环中,for循环的()相当于父级作用域,{ } 相当于()的子级作用域。子级作用域中的局部变量不会影响父级作用域中的变量。 在if(){}、while(){}中也是一样的道理。代码验证如下:
for(let i=0;i<3;i++){
let i = "abc";
console.log(i);
}//最后打印结果为3个“abc”,如下图
let和const的区别:
- const定义变量后不能修改(即用于定义常量);
- const定义变量的同时必须赋值,不能先定义后赋值,赋值后不可修改;
- const定义数组/对象后,使用方法可改变数组/对象的值。若想使数组/对象不可改变值,必须使用Object.freeze(对象)进行数组/对象的冻结,代码验证如下图。
(PS:其实数组也是一种特别的对象)
【本质】const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
引自:阮一峰的ES6入门 - let 和 const 命令
关于块级作用域:
- 有一个需要注意的地方。ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。
// 第一种写法,报错
if (true) let x = 1;
// 第二种写法,不报错
if (true) {
let x = 1;
}
- 块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式(匿名 IIFE)不再必要了。
// IIFE 写法
(function () {
var tmp = ...;
...
}());
// 块级作用域写法
{
let tmp = ...;
...
}
注意
ES6 一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1
let b = 1;
window.b // undefined
上面代码中,全局变量a由var命令声明,所以它是顶层对象的属性;全局变量b由let命令声明,所以它不是顶层对象的属性,返回undefined。
引自:阮一峰的ES6入门 - let 和 const 命令