ES6 let 和 const
在ES6以前,变量的定义通常是使用var关键字,在函数作用域或者全局作用域中使用var定义的变量,都会被提升到顶部(变量声明),这就叫变量声明提升,例子:
function getValue(){
if(condition){
var value = 'blue';
return value;
}else{
// 此处可以访问value
return null;
}
// 此处可以访问value
}
上述value变量看似是在condition内声明初始化的,实际上,它的声明会被提升到函数顶部,类似下面:
function getValue(){
var value; // 因为没有初始化,值为undefined
if(condition){
value = 'blue';
return value;
}else{
// 此处可以访问value
return null;
}
// 此处可以访问value
}
1. 块级声明
ES6 中引入了两个关键字let和const来定义块级变量,用于声明在作用域外无法访问的变量,可存在于:
(1)函数内部
(2)块中(字符{和}之间的区域)
let 声明
let声明用法和var一样,用let 来代替 var,可以把变量的作用域限制在当前代码块中
但是let 声明不会被提升,因此通常将let声明语句放在块的顶部,例如:
function getValue(){
if(condition){
let value = 'blue'; // 用let声明的变量,当执行流离开了if块,value立刻被销毁
return value;
}else{
// 此处value不存在
return null;
}
// 此处value不存在
}
(1)禁止重复声明

在同一作用域中不能用let重复定义已经存在的标识符,
如果在不同作用域中,则可以

没有报错,在{ }作用域中,let定义中的a 会覆盖全局中的a
const 声明
使用const 声明的是常量,一旦定义就无法修改,也会产生块级作用域,但是定义的时候必须同时初始化

同样也只存在于块级作用域,外部无法访问
无法重复声明

const 与 let 的不同之处
无论是在严格还是非严格模式下,使用const定义的变量都无法再赋值,而let 可以

const 声明对象

person 变量指向带有name属性的对象,使用const定义,可以修改其属性的值,但是不能修改其指向
临时死区(TDZ)
与var不同,使用const和let声明的变量不会被提升到作用域顶部,如果在声明之前访问这些变量,即使是相对安全的typeof操作也会触发引用错误,

但是单独执行这个操作
没有报错!!!
为什么呢,因为在输出语句执行的时候,let 初始化ccc的行为还没有执行,
此时的ccc 还位于JavaScript社区所谓的“临时性死区”中,换成const也一样
JavaScript引擎在扫描代码发现变量声明时,要么将它们提升到作用域顶部(遇到var声明),要么将它们放入临时性死区(遇到let,const声明)
访问临时性死区中的变量会触发运行时错误,直到他们被声明(const还需要初始化),变量才会从临时性死区(TDZ)中移出,才可正常访问。
但是在let声明的作用域外访问就不会出错,

循环中的块作用域绑定
类似下述代码:

for 循环内用var声明i变量,在for循环外仍然可以访问,因为 i 变量进行了提升

改用let声明变量,则不能在外部访问,
使用var声明,看下列代码
var funcs = [];
for(var i=0;i<10;i++){
funcs.push(function(){
console.log(i)
});
}
funcs.forEach(function(func){
func();
});
我们预期上述输出0-9,但实际呢,输出10次10!

因为循环里每次迭代都共享着同一个i,循环内部创建了10个函数,引用着同一个i,循环结束的时候i的值为10,所以每次调用输出10,
为了解决这个问题,ES5中 我们可以用闭包+IIFE(立即调用表达式)来解决,代码如下:

注意,立即执行表达式外部得用()包起来,IIFE为每一个i变量都创建了一个副本并存储为value
上述代码看似有些多了,在ES6中,我们可以用let来解决这个问题,代码如下:

使用let声明i时,每个循环都会创建一个新的i变量,在一个独立的作用域中,所以内部创建的每个函数都能得到一个自己的i副本
对于for-in 循环 和 for-of 循环也是一样的,示例:

因为每次循环都会创建一个新的key绑定,因此每个函数都有一个key的副本
若使用var声明key,则都会输出c

在循环中若要使用const变量,需要保证后续不会对const所定义的值进行修改,
在普通for循环中会报错,但是在for-in,for-of中可以使用

因为在循环内不会改变key的值
全局块作用域绑定
let 和 const 与var 的另一个区别是它们在全局作用域内的行为。
当var被作用于全局作用域时,它会创建一个新的全局变量作为全局对象(浏览器环境中的window对象)
这意味着用var很可能会覆盖一个已经存在的全局变量,就像这样:

但如果你在全局作用域中使用let或const,会在全局作用域下创建一个新的绑定,但该绑定不会添加为全局对象的属性,不会覆盖全局变量,而只能遮蔽它
如下:

所以如果不想为全局创建属性,则使用let和const要安全得多。
总结:
当我们使用块级绑定时,默认使用const,只在确实需要修改变量的值时候使用let。这样就可以在某种程度上实现代码的不可变,从而防止某些错误的产生。

浙公网安备 33010602011771号