【JS】谈谈var、let的区别
前言
学习JavaScript的小伙伴是否有过被 var 和 let 弄得很疑惑的时候呢?如果有,请认真看完本文,一定会对你有很大的帮助。
正文
var
、let
是 JavaScript 中用于声明变量的两种关键字,它们之间有一些区别。
-
var:
var
是在 ES5 中引入的变量声明关键字。- 它具有函数作用域,而不是块作用域。这意味着当你使用
var
声明变量时,它会提升到最接近的函数作用域的顶部。 - 如果在同一个作用域内使用
var
多次声明同名变量,后面的声明会覆盖前面的声明。 var
声明的变量可以在声明之前被访问(变量提升)。
-
let:
let
是在 ES6 中引入的块级作用域变量声明关键字。- 它具有块级作用域,意味着它的作用域限制在它所在的块(大括号
{}
)内部。 - 使用
let
声明的变量不会像var
那样被提升。这意味着你不能在声明之前访问使用let
声明的变量。 - 同一个块作用域内不能使用
let
声明同名变量,否则会报错。
这样看大家可能还不是很懂,我用几段代码让大家加深理解:
例如声明的提升,对于var声明的变量,具有声明提升的特性
a = 2
var a
console.log(a) //2
可能你会说变量a
的声明不是在a = 2
之后吗?那么这就是声明提升的奥妙之处了!简单来说,当你使用 var
声明变量时,它会提升到最接近的作用域的顶部。
但是可能有的人就会问了:
var a
console.log(a) //undefined
a = 2
为什么这里是undefined的呢?那么我告诉你,提升只对变量和函数的声明有用,但是对变量的赋值操作或者函数的调用操作来说,没有提升这一回事。 所以console.log(a)
的执行顺序先于a = 2
,所以输出undefined。
那么对于es6新增的let
关键字就更有意思:
a = 2 //ReferenceError
let a
console.log(a);
很明显,let
声明的变量也不存在提升,所以我们必须按照写C语言那般,严格按照代码执行顺序书写。它具有块级作用域,意味着它的作用域限制在它所在的块,这一点可以让let
在某些var
难以解决的问题上产生奇效。
实战
大家可以想想下面的代码:
for(var i =0;i<5 ; i++){
setTimeout(() => {
console.log(i);
},500)
}
这段代码的初衷是输出0、1、2、3、4,且时间间隔是500ms,但是结果大跌眼镜,是五个5。这究竟是为什么呢?
在这个例子中,使用 var
关键字声明的变量 i
具有函数作用域,而不是块级作用域,在这里i是属于全局的。在 JavaScript 中,setTimeout
回调函数是在循环完成后才执行的,因此当回调函数执行时,i
的值已经是循环结束后的值,即 5
。
解决方案:
for (var i = 0; i < 5; i++) {
(function (j) {
setTimeout(() => {
console.log(j);
}, 500);
})(i);
}
这里有几个点需要注意,( function(){....} )() 是立即执行函数,即每循环一次调用一次,再去通过传参的方式将i传入闭包函数内部的作用域,以保证每轮循环迭代能够将i保存下来,这样,每个回调函数将会捕获到循环迭代时 i
的值,而不是最终的 5
。
2. 现在可以请我们的let
登场了:
for(let i =0;i<5 ; i++){
setTimeout(() => {
console.log(i);
},500)
}
没错,把var
改成let
即可,就这么简单。使用 let
关键字声明的变量 i
具有块级作用域,每次迭代循环都会创建一个新的 i
,而不是共享同一个 i
,并且每个 i
的作用域都是在当前循环迭代中。 因此,每个 setTimeout
回调函数捕获到的 i
都是当前迭代中的值,而不是循环结束后的值。
最后
希望大家不用再对 var 和 let 疑惑了,弄清楚var
和let
对今后JS的学习都会有很大的帮助。
后期我还会更新let
的详解,有兴趣的小伙伴记得点赞和关注我哦!
如果你也在准备春招,欢迎加我微信lyhGetup,一起交流,一起刷面经。