【JS】谈谈var、let的区别

前言

学习JavaScript的小伙伴是否有过被 var 和 let 弄得很疑惑的时候呢?如果有,请认真看完本文,一定会对你有很大的帮助。

正文

var let 是 JavaScript 中用于声明变量的两种关键字,它们之间有一些区别。

  1. var

    • var 是在 ES5 中引入的变量声明关键字。
    • 它具有函数作用域,而不是块作用域。这意味着当你使用 var 声明变量时,它会提升到最接近的函数作用域的顶部。
    • 如果在同一个作用域内使用 var 多次声明同名变量,后面的声明会覆盖前面的声明。
    • var 声明的变量可以在声明之前被访问(变量提升)。
  2. let

    • let 是在 ES6 中引入的块级作用域变量声明关键字。
    • 它具有块级作用域,意味着它的作用域限制在它所在的块(大括号 {})内部。
    • 使用 let 声明的变量不会像 var 那样被提升。这意味着你不能在声明之前访问使用 let 声明的变量。
    • 同一个块作用域内不能使用 let 声明同名变量,否则会报错。

这样看大家可能还不是很懂,我用几段代码让大家加深理解:

例如声明的提升,对于var声明的变量,具有声明提升的特性

css 复制代码
    a = 2
    var a 
    console.log(a) //2

可能你会说变量a的声明不是在a = 2之后吗?那么这就是声明提升的奥妙之处了!简单来说,当你使用 var 声明变量时,它会提升到最接近的作用域的顶部。

但是可能有的人就会问了:

css 复制代码
    var a 
    console.log(a) //undefined
    a = 2

为什么这里是undefined的呢?那么我告诉你,提升只对变量和函数的声明有用,但是对变量的赋值操作或者函数的调用操作来说,没有提升这一回事。 所以console.log(a)的执行顺序先于a = 2,所以输出undefined。

那么对于es6新增的let关键字就更有意思:

css 复制代码
    a = 2 //ReferenceError
    let a
    console.log(a); 

很明显,let声明的变量也不存在提升,所以我们必须按照写C语言那般,严格按照代码执行顺序书写。它具有块级作用域,意味着它的作用域限制在它所在的块,这一点可以让let在某些var难以解决的问题上产生奇效。

实战

大家可以想想下面的代码:

css 复制代码
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

解决方案:

1. 使用我们之前讲过的闭包,在setTimeout外部再嵌套一个函数形成闭包 ,如果大家对闭包还不是很了解可以参考我之前的文章【JS】"编程中的魔法:深入理解闭包"复习一下。

ini 复制代码
for (var i = 0; i < 5; i++) {
    (function (j) {
        setTimeout(() => {
            console.log(j);
        }, 500);
    })(i);
}

这里有几个点需要注意,( function(){....} )() 是立即执行函数 ,即每循环一次调用一次,再去通过传参的方式将i传入闭包函数内部的作用域,以保证每轮循环迭代能够将i保存下来,这样,每个回调函数将会捕获到循环迭代时 i 的值,而不是最终的 5

2. 现在可以请我们的let登场了:

scss 复制代码
for(let i =0;i<5 ; i++){
    setTimeout(() => {
        console.log(i);
    },500)
}

没错,把var改成let即可,就这么简单。使用 let 关键字声明的变量 i 具有块级作用域,每次迭代循环都会创建一个新的 i,而不是共享同一个 i,并且每个 i 的作用域都是在当前循环迭代中。 因此,每个 setTimeout 回调函数捕获到的 i 都是当前迭代中的值,而不是循环结束后的值。

最后

希望大家不用再对 var 和 let 疑惑了,弄清楚varlet对今后JS的学习都会有很大的帮助。

后期我还会更新let的详解,有兴趣的小伙伴记得点赞和关注我哦!

如果你也在准备春招,欢迎加我微信lyhGetup,一起交流,一起刷面经。

相关推荐
顾凌陵几秒前
CSRF&SSRF漏洞攻击的溯源分析与实战
前端·csrf
用户6919026813392 分钟前
JS 初了解:从“网页玩具”到企业级语言的进化
javascript
月月大王的3D日记2 分钟前
Three.js 材质篇(中):从兰伯特到PBR,一篇文章看懂五种光照材质
前端·javascript
且白3 分钟前
leaflet切片变色、地图滤镜逻辑实现 colorfilter
前端·javascript
用户887665426638 分钟前
Linux 终端入门:新手必须掌握的常用命令和基本思路
前端·操作系统
丷丩15 分钟前
MapLibre GL JS第30课:添加视频
javascript·音视频·gis·mapbox·maplibre gl js
techdashen15 分钟前
拆开任意 Electron 应用:从 Windows 安装包到 Discord 的私有更新协议
javascript·windows·electron
用户1257585243619 分钟前
Vue3 后台框架的网络请求怎么设计?看 XYGo Admin 三套 Axios 实例与拦截器方案
前端
ZengLiangYi22 分钟前
多格式文件解析:JSONL / SQLite / Event Stream
前端·javascript·后端
jiayong2323 分钟前
Kafka 高吞吐消息链路常见面试问题及详细解答
分布式·面试·kafka