Skip to content

在 ES 6 中,提出了 let 关键字来声明变量,同时,建议你声明变量应该避免使用 var 关键字,而采用 let 关键字。只需要使用 let 关键字来声明变量,就可以非常好地解决 JS 中变量存在的问题。

js
let a = 1;
console.log(window.a);//let声明的关键字并不会挂载到全局对象

let a = 2;//报错,不允许使用let重复声明变量

for(let i = 0;i < doms.length;i++){
	doms.onclick = function(){
		console.log(i);//这样绑定是正确的
	}
}

综上,我们其实可以总结出以下几个优势

  • let 声明的变量不会挂载到全局对象
  • let 声明的变量不允许在当前作用域内重复声明
  • let 声明的变量为块级作用域,不会产生闭包问题

ES 6 引入了块级作用域解决了闭包带来的一系列问题,所谓的块级作用域,就是以大括号为范围的作用域,也就是说当遇到一个大括号就会创建一个块级作用域,大括号结束就会销毁块级作用域。

js
let a = 1;
{
	let a = 2;
	console.log(a);//2
}
console.log(a);//1

这个代码是不报错的,因为 let a = 2 这个代码是在大括号里面的,并不是全局作用域。由于块级作用域出了作用域就会立刻销毁,所以在作用域中用 let 定义的变量在作用域外不能访问。这和其他语言很类似。块级作用域其实非常简单,就是以大括号为分割,里面的能用外面的,外面的不能用里面的,仅此而已。

使用 let 关键字声明的变量是不会有变量提升的,所以在声明之前是不能使用的。但实际上,从底层来说,let 声明的变量依然会有变量提升,提升后会放到暂时性死区,如果访问的变量位于暂时性死区就会报错,直到代码运行到该变量的声明语句的时候,才会将其从暂时性死区拿出来,此时才可以对他进行操作。虽然底层他也有变量提升,但在我们程序员的视角来看,实际上 let 声明的变量我们完全可以认为其没有变量提升。

对于循环来说,会有一个特殊处理。在每一次循环都会开启一个新的块级作用域,并且将循环变量绑定到该作用域,也就是说每次循环使用的其实是全新的变量。

js
for(let i = 0;i<2;i++){
	//somecode
}

//实际上上面的代码类似于下面:
{
	let i = 0;
	//somecode
}
{
	let i = 1;
	//somecode
}

实际上,上面的写法是等价的,我们可以看到,实际上,每次循环他的 i 是自己作用域的 i,每一次的 i 是不一样的,所以当使用 for 循环来循环绑定事件的时候,也就不会产生以前那种奇奇怪怪的问题。同时,读者也应该能看到,循环变量在循环结束之后是会被销毁的,注意,这一点很多时候并不是我们想要的,因为循环变量有时候可以用来做一些条件判断,即判断循环是以何种方式结束的,如果我们不希望循环变量在循环结束后被销毁,可以考虑在外部声明循环变量。

以笔记为镜,可以知得失