1 为什么ES6要引入let和const(var命令所存在的问题)
1.1 变量提升
if (false) { var a = 1}console.log(a)
正常理解上,if语句判定为false,var a = 1不会执行,最后 console.log(a)应该会报错才对,但实际结果为undefined。 导致这个结果的原因就是变量提升,上述代码可以理解为
var aif (false) { a = 1}console.log(a) // undefined
这样结果就显而易见了。
1.2 没有块级作用域
一个老生常谈的面试题
var funcs = []for (var i = 0; i < 3; i++) { funcs[i] = function () { console.log(i); };}funcs[0]() // 3
因为没有块级作用域,所以 i 泄漏为全局变量,funcs数组中方法所引用的变量 i 都是这一全局变量,导致函数并没有如预想的方式对变量i进行输出 0 1 2
1.3 可以重复声明
var a = 1var a = 2console.log(a) // 2
变量可以被重复的声明,可能会导致程序产生意想不到的bug
1.4 在全局作用域中声明的变量会创建为全局变量作为全局对象的属性
var a = 1console.log(window.a) // 1
2 let和const与var的区别
引入let和const就是为了解决上述var所存在的问题,这也就两者之间的区别
不会进行变量提升块级作用域不可以重复声明不会创建为全局对象的属性可以使用上面的例子进行检测
3 let和const之间的区别
3.1 let声明的变量可以重新赋值,const声明的则不可以,所以const在声明变量时就一定要进行初始化
let a = 1a = 2 // 2const b = 1b = 2 // Uncaught TypeError: Assignment to constant variable.
const声明不允许重新赋值,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动,但允许修改值。这意味着当用const声明对象时,对象的修改就是不可控的了
const obj = { propName: 1}obj.propName = 2 // 2 这样是完全可以的
4 暂时性死区
let与cosnt声明的变量,在声明之前,该变量都是不可用的,这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)
var a = 1function foo () { console.log(a) let a = 2}foo() // Uncaught ReferenceError: a is not defined
这段代码,按照let声明的变量不会进行变量提升理解时,foo方法中console.log(a)应该查找到全局的变量a,打印出2才对。为什么会报错呢? 这就是因为暂时性死区 JavaScript 引擎在扫描代码发现变量声明时,要么将它们提升到作用域顶部(遇到 var 声明),要么将声明放在 TDZ 中(遇到 let 和 const 声明)。访问 TDZ 中的变量会触发运行时错误。只有执行过变量声明语句后,变量才会从 TDZ 中移出,然后方可访问。所以在声明foo方法时,函数内部的a已经被放到TDZ中,在未执行声明语句前使用都会报错。 上面的代码段也可以理解为只要块级作用域内存在let const命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响
5 总结
let 和 const 的出现解决了 var 声明变量时存在的一系列问题,所以目前的最佳实践是:默认使用 const,只有当确实需要改变变量的值的时候才使用 let。这是因为大部分的变量的值在初始化后不应再改变,而预料之外的变量值的改变是很多 bug 的源头。
(源于网络,侵删)