let和var变量声明区别

var声明的变量是没有块级作用域的:
eg:

{
	var a = 10;
}
console.log(a); //a = 10

let声明的变量具有块级作用域
eg:

{
	let a = 10;
}
console.log(a); //报错,a is not defined

下面我们来看一个常见的面试题:

for (var i = 0; i < 3; i++) {
	console.log(i); //0 1 2
	setTimeout(function(){
		console.log(i);  // 3 3 3
	}, 0);
}

输出结果为什么会是这样的呢?
因为var声明的i是一个全局变量,第一个console.log(i)是一个同步任务,所以在i依次被重定值时会一起变化,而在第一次循环时发现了定时器,由于它是属于异步任务,所以它不会马上执行,而是把它扔进了事件侦听模块,计时到了,就会把它放进任务队列里去,等待同步任务执行完毕时再回头看任务队列里是否有任务,若有,则会执行,此时i早已变成了3了,第n次循环亦是如此…
这里可以参照同步和异步任务详解:https://segmentfault.com/a/1190000011198232
若想定时器里的i依次输出呢?我们有几种方法:
我们可以加个自执行函数传个实参,这样可以把全局变量下的i变成局部变量。

for (var i = 0; i < 3; i++) {
	console.log(i); //0 1 2
	(function(i) {
		setTimeout(function(){
		console.log(i);  // 0 1 2
		}, 0);
	})(i);
}	

而下面把var变成let呢?

for (let i = 0; i < 3; i++) {
	console.log(i); //0 1 2 
	setTimeout(function(){
		console.log(i);  // 0 1 2 
	}, 0);
}

结果得到我们期待的值,这是因为什么呢?
因为我们知道let声明的具有块级作用域,它现在就是一个局部变量,每一次的i声明都是单独的

下面我们来详写这个过程:
var声明的i相当于执行如下操作:

{
	var i = 0;
	setTimeout(function(){console.log(i)}, 0) // i = 2
}
{
	var i = 1;
	setTimeout(function(){console.log(i)}, 0) // i = 2
}
{
	var i = 2;
	setTimeout(function(){console.log(i)}, 0) // i = 2
}

let:

{
	let i = 0;
	setTimeout(function(){console.log(i)}, 0) // i = 0
}
{
	let i = 1;
	setTimeout(function(){console.log(i)}, 0) // i = 1
}
{
	let i = 2;
	setTimeout(function(){console.log(i)}, 0) // i = 2
}

let声明的变量只在自己的块级区域有效,所以是单独存在的哟!!

猜你喜欢

转载自blog.csdn.net/qq_48784569/article/details/107486529