众所周知,js中对var声明有变量提升机制,所以ESMAScript6使用块级作用域来加强对变量生命周期的控制。让const声明不会被提升。有几点需要注意:1.不能重复声明假设一个标识符已经存在于作用域中(不管这个标识符是通过var还是let或者const变量声明来声明的),那么此时使用let或者const键来声明都会throwanerrorvarcount=10letcount=20//这个地方会抛出一个错误,因为在同一个作用域内不能重复声明如果当前作用域嵌入了另一个作用域,可以使用let来声明一个变量嵌入范围内同名varcount=10if(true){letcount=20}2.const声明的常量必须初始化。如果声明如下,会报错constname;//语法错误,常量未初始化3.不能对const定义的常量进行重新赋值。真正的本质是const声明不允许修改,绑定是固定的,但是允许修改值(也就是说const声明了对象后,可以修改对象的属性值)const人={name:'angela'}//可以修改对象属性的值person.name='yun'//修改绑定会抛出语法错误person={'name':'Shining'}4.TemporalDead区域(TemporalDeadZone)当JavaScript引擎扫描代码发现变量声明时,要么将它们提升到作用域的顶部(遇到var声明),要么将声明放入TDZ(遇到let和const声明),访问变量inTDZ会触发runtimeerror,只有在变量声明语句执行完后,变量才会从TDZ移动到正常访问下面的代码是因为在if中执行console.log的时候value已经在TDZ中了块级范围。在过去,typeof是一个相对不会出错的操作符,但实际上,它并不能阻止引擎抛出一个错误来访问声明之前的块级别。绑定会导致错误,因为绑定处于临时死区if(true){console.log(typeofvalue)//referenceerrorletvalue='blue'}并且在let范围之外的这个变量上使用typeofdeclaration不会报错console.log(typeofvalue)if(true){letvalue='blue'}5.在块级作用域绑定之前在循环中创建函数有点难以形容varfuncs=[]for(vari=0;i<10;i++){funcs.push(function(){console.log(i)})}funcs.forEach(function(func){func()})因为在循环内创建的函数都保留对同一变量的引用。循环结束时,变量i的值为10,所以结果会输出10乘以10。所以大家会在循环中使用立即调用函数表达式强制生成计数器变量,使其输出1,2,3...varfuncs=[]for(vari=0;i<10;i++){funcs.push((function(value){returnfunction(){console.log(value)}})(i))}funcs.forEach(function(func){func()})使用let,可以简化立即调用函数表达式,实际上,循环的每次迭代都会创建一个新的Variable,并用上次迭代中同名变量的值varfuncs=[]for(leti=0;i<10;i++){//实际上每次循环时let声明都会创建一个新变量iand将其初始化为i的当前值,因此在循环内创建的每个函数都获得自己的ifuncs.push(function(){console.log(i)})}funcs.forEach(function(func){func()//这里的输出是0然后是1,2...9})这个特性同样适用于forin,比如varfuncs=[],obj={a:true,b:true,c:true}for(letkeyinobj){funcs.push(function(){console.log(key)})}funcs.forEach(function(func){func()//outputisabc})6.let声明特性intheloop也适用于const声明。唯一的区别是const不能改变绑定。在上面的例子中,让改成const也输出abcvarfuncs=[],obj={a:true,b:true,c:true}//之所以可以使用forin和forof循环,是因为每次迭代都不会修改已经存在的有一个绑定,但是会创建一个新的绑定for(constkeyinobj){funcs.push(function(){console.log(key)//也输出abc唯一不同的是key的值不能在循环内改变})}funcs.forEach(function(func){func()})下面的例子会报错,因为在for循环中改变了i的绑定,const常量不能改变绑定varfuncs=[]for(consti=0;i<10;i++){funcs.push(function(){console.log(i)})}funcs.forEach(function(func){func()})7.全局作用域绑定当var应用于全局作用域时,会创建一个新的全局变量,作为全局对象(浏览器环境中的window对象)的属性,这意味着使用var很可能会不经意地覆盖一个已经存在的globalvariablefrom从上面的代码可以看出,即使是全局对象RegExpArray也会被覆盖,但是let或者const会在全局范围内创建一个新的绑定,但是绑定不会作为全局对象的属性添加,换句话说,使用let或const不能覆盖全局变量,而只能覆盖它RegExp和window.RegExp此时是不一样的letRegExp='hello'console.log(RegExp)//helloconsole.log(window.RegExp===RegExp)//falseconstncz='hi'console.log(ncz)console.log("ncz"inwindow)最佳实践:默认使用let代替varconst,只在真正需要的时候使用let需要改变变量的值
