当前位置: 首页 > Web前端 > JavaScript

消失的var

时间:2023-03-27 13:44:30 JavaScript

作者:温荣骄相信大部分接触过前??端开发的朋友都对var关键字非常熟悉,但是在现代工程中,你会发现var关键字正在被废弃,有的甚至使用lint(eslintno-var)工具显式禁用var,并且var关键字正在消失。1.var的定义MDN文档对var的描述是:变量声明,无论出现在什么地方,都在任何代码执行之前被处理。用var声明的变量的范围是它当前的执行上下文,它可以是一个嵌套函数,或者对于在任何函数之外声明的变量来说是全局的。如果您重新声明一个JavaScript变量,它不会丢失它的值。描述的第一句是指var的变量提升特性,最后一句是指var变量的可重声明特性。这两个特性在给开发者带来方便的同时,也带来了一些变量值的异常。例如:vara=1;//其他逻辑代码functiona(){}console.log(a);//上面1的代码中,首先声明了a变量并赋值1,然后声明了a函数。开发者打算执行函数a,但是在开发过程中忘记声明a,导致a被赋值1,出现异常。浏览器对上述代码的处理如下vara;functiona(){}a=1;console.log(a)2.var的特点和缺陷我们在var的定义部分用例子演示了var变量的提升和变量重声明特性及其给开发者带来的困惑。2.1变量提升在js解析过程中,由于变量声明(和其他声明)总是在任何代码执行之前处理,所以在代码中的任何地方声明变量总是等同于在代码开头声明它们。这意味着变量可以在声明之前使用,这种行为称为“提升”。“提升”就像将所有变量声明移动到函数或全局代码的开头。vara=1;console.log(b);//undefinedvarb=2;console.log(b);//2浏览器会将其解析为vara;varb;a=1;console.log(b);b=2;console.log(b);变量提升看起来很漂亮,开发者可以在同一范围内的任何地方声明变量。但是也带来了一个潜在的风险,比如:vara=1;functionfn(){//开发者想访问上层作用域的a变量console.log(a);//其他代码逻辑//这里,开发者忘记了上面的程序已经访问了a变量,而声明了一个局部变量avara={}//其他逻辑}出现问题,开发者想访问值1a的,实际的值是undefined,但是我们调试断点的时候,并不能直观的反映出a已经声明在函数的局部作用域内。2.2变量重声明用var关键字声明的变量可以重声明而不会丢失它的值`vara=1;vara;console.log(a);//1`被重新声明,值还是1。同样,过于松散的声明规则也带来了一些问题。当然,仅仅重声明对原来的变量没有影响,但是我们通常是在重声明之后配置赋值逻辑。这会造成什么问题,我们还是看第一节的例子vara=1;//其他逻辑代码functiona(){}console.log(a);//1a已经被重新声明了,但是开发者没有感知到,导致a又被赋值给了1。2.3无块作用域在JS中,作用域分为全局作用域和局部作用域。在es5之前,创建局部作用域的方式只能通过function(){}函数创建,即'{}'不会在es5之前创建作用域,这也导致if/while语句中声明的变量也被提升到范围的顶部if(0){vara=1;}console.log(a);//undefined这给开发人员带来了极大的困惑,无法访问的代码实际上会影响程序。在此示例中,浏览器将其处理为vara;if(0){a=1}console.log(a);在JS中使用未声明的变量时,浏览器会将其挂载到window对象Down。如何证明上面的例子是变量被提升而不是被挂载到窗口的顶层对象上。让我们改变例子“usestrict”;如果(0){vara=1;}console.log(a);//undefined我们启用了严格模式(strictmode),我们知道严格模式变量中不能使用undeclared。但是变量a的值仍然是undefined,说明浏览器确实推动了条件循环语句中var声明变量的声明。{vara=1;}console.log(a);//13.Alternativeletconst3.1javascript发展历程上面我们举了很多例子来说明var的特性,也体验过var可能带来的额外异常。幸运的是,ECMA规范制定者也在不断完善和丰富JS语法。下表列出了JS版本的时间节点和主要变化。作为一名前端开发者,我深知es6的重要性。让我们看看es6(es2015)带来了什么。先不说class和extend的引入,ArrayObject对象方法的丰富。下面来看看let和const关键字的介绍。3.2letMDN对let的描述是:let允许你声明一个变量、语句或表达式,其作用域被限制在块级别。与var关键字不同,var声明的变量只能是全局的或整个功能块。3.21var与var变量提升的对比相应地,let有一个临时死区的特性,即let声明的变量直到其定义被执行时才被初始化。在变量初始化之前访问它会导致ReferenceError。变量处于从块顶部到初始化处理的“临时死区”。控制台日志(一);//ReferenceErrorleta=1;let声明的变量将创建块级作用域{leta=1;}console.log(a);//ReferenceError不能重复leta=1;leta=2;//UncaughtSyntaxError:Identifier'a'hasalreadybeendeclared这在语法上限制了变量覆盖的可能性。特别是在switch语句中只有一个块时,会发生以下错误。letx=1;switch(x){case0:leta;休息;情况1:让a;//UncaughtSyntaxError:Identifier'a'hasalreadybeendeclaredbreak;}使用{}块创建块动作域,上面的重复声明不会有问题letx=1;switch(x){case0:{让一个;休息;}案例1:{让一个;休息;}}让我们回顾一下我们之前模块化处理的经典做法,用自执行函数包装模块代码。基于let语法的块作用域特性,我们在处理模块化时是否还有一种直接用'{}'包装的额外形式。当然,在现代前端工程中,已经将单个文件作为一个模块,我们的代码不需要自己去处理模块化。3.3const该声明创建一个常量,其范围可以是全局或局部声明的块。与var变量不同,全局常量不会成为window对象的属性。需要常量的初始化器;也就是说,您必须在声明它的同一语句中指定它的值(这是有道理的,因为它以后不能更改)。const和let的特点很相似——const声明的变量引用值不能改变;-const声明的变量必须在声明时进行初始化。4.总结var声明变量提升和可重复声明的特点,很容易造成变量覆盖导致的值异常。letconst是一种语法更严格的设计,限制了语法本身,避免了变量覆盖的问题,创造了更安全的块作用域。综上所述,建议开发时统一使用es6语法,放弃使用var关键字。加入no-var规则并拥抱letconst。5.参考文档VAR描述https://developer.mozilla.org...LEThttps://developer.mozilla.org...CONSThttps://developer.mozilla.org...MDNhttps://developer.mozilla。org...no-varhttps://eslint.bootcss.com/do...ES6https://www.w3cschool.cn/ecma...