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

关于 var,let和const 关键字定义变量的一些归纳

时间:2023-03-26 22:56:17 JavaScript

constconst声明创建块作用域常量,很像使用let关键字声明的变量。常量的值不能通过重新分配(即通过使用赋值运算符)更改,也不能重新声明(即通过变量声明)。然而,如果一个常量是一个对象或数组,它的属性或项可以被更新或删除,常量是块作用域的,很像使用let语句定义的变量。但是常量的值不能改变(通过重新赋值),也不能重新声明。文档中介绍了做法://eg1:consta=12if(a){consta=10console.log(a)}console.log(a)//console:>10>12//eg2:consta=newObject({name:'jack'})constb=newObject({name:'jack'})a.name='peters'deleteb.nameconsole.log(a,b)//console:>[objectobject]{name:"peters"},[objectObject]{...}//eg3:/*数组shift方法用于删除数组的第一个元素arraypop方法用于删除数组的最后一个元素array*/consta=newArray(1)constb=newArray(1)a[0]='peters'b.shift()//[]结果与pop()console.log(a,b)//console:>["peters"],[]要点:block-scoped(块作用域)值不能改变,也不能重新声明(常量的值不能改变,并且常量不能被重新声明)在同一个声明中它的值必须在语句中指定(因为声明的常量值不能改变)但是,如果常量是一个对象或数组,它的属性或项目可以被更新或删除d(当const定义的常量是一个对象或数组时,它们的属性或项(数组中的一项或项)可以通过赋值来更新或移除(删除))varvar语句声明一个函数作用域或全局-作用域变量,可选择将其初始化为一个值。var语句用于声明一个函数范围或全局范围的变量,可以初始化为一个值(可选)文档说明vardeclarations,无论它们出现在哪里,都会在任何代码执行之前被处理。这称为提升,将在下面进一步讨论。用var声明的变量的范围是其当前执行上下文及其关闭(它是封闭函数和在其中声明的函数),或者对于在任何函数外部声明的变量,是全局的。使用var的重复变量声明不会触发错误,即使在严格模式下,变量也不会丢失其值,除非执行另一次赋值。在执行任何代码之前,将在任何地方声明一个变量。这称为变量提升。用var声明的变量的范围是它的当前执行上下文和它的闭包(嵌套函数),或者对于在任何函数之外声明的变量。它是全球性的。用var重复声明一个JavaScript变量不会抛出错误(即使在严格模式下),并且在调用另一个赋值之前变量不会丢失其值。提升(变量提升)因为在执行任何代码之前处理var声明,所以在代码中的任何地方声明一个变量等同于在顶部声明它。这也意味着一个变量可以在它被声明之前看起来是被使用过的。这种行为称为提升,因为看起来变量声明已移动到函数或全局代码的顶部。由于变量声明(和其他声明)总是在任意等同于在代码开头声明之前处理。这意味着变量可以在声明之前使用,这种行为称为“提升”。“提升”就像将所有变量声明移动到函数或全局代码的开头。练习//eg1:vara=1if(a==1){vara=2console.log(a)}console.log(a)//console:>2>2//eg2:functionfoo(){变量x=1;函数bar(){变量y=2;控制台日志(x);//1(函数`bar`包含`x`)console.log(y);//2(`y`在范围内)}bar();控制台日志(x);//1(范围内的`x`)console.log(y);//将在严格模式下抛出ReferenceError,`y`仅在`bar`函数的范围内}foo();//console:>1>2>1>"UncaughtReferenceError:yisnotdefined"//eg3:vara,b(function(){console.log(a)console.log(b)vara=(b=3)console.log(a)console.log(b)})()console.log(a)console.log(b)//console:>undefined>undefined>3>3>undefined>3ExtendedInterpretationIIFE(immediatelyinvokedfunctionexpression)这是一种称为自执行匿名函数的设计模式,主要包括两部分。第一部分是一个用圆括号()包围的匿名函数,它有自己的词法作用域。这样既可以防止外界访问这个IIFE中的变量,也不会污染全局作用域。第二部分再次使用()创建一个立即函数表达式,JavaScript引擎将直接执行该函数。variableinkeypointsfunctionscopeorglobalscope==>作用域是它当前的执行上下文和它的闭包(嵌套函数),可以初始化为一个值(可选),如果没有初始化,就是未定义的变量提升==>在代码中的任何地方声明一个变量总是等同于声明letlet声明声明一个块作用域的局部变量,可选择将其初始化为一个值。let语句在代码的开头声明了一个块作用域的局部变量,并且可以初始化为一个值(可选)。文档描述描述let允许您声明仅限于块语句或使用它的表达式的范围的变量,这与var关键字不同,后者在全局或局部声明整个函数的变量而不管块范围。var和let之间的另一个区别是后者只能在到达其声明后才能访问(请参阅临时死区)。出于这个原因,let声明通常被认为是非提升的。就像const一样,let在全局声明时(在最顶层范围内)不会创建窗口对象的属性。为什么选择名称“let”的解释可以在这里找到。通过在使用它们的范围的顶部声明它们可以避免let变量的许多问题(这样做可能会影响可读性)。与var不同,let开始声明,而不是语句。这意味着你不能使用单独的let声明作为块的主体(这是有道理的,因为没有办法accessthevariable).let允许你声明一个变量、语句或表达式,其范围被限制在块范围内。与var关键字不同,var声明的变量的作用域是全局的或者整个功能块。var和let的另一个重要区别是let声明的变量不会在作用域中被提升,它会在编译时被初始化(参考下面的临时死区)。与const一样,let在全局声明时(在最顶层范围内)不会创建window对象的属性。你可以在这里了解我们为什么使用let。您可以通过在使用它们的范围的顶部声明let变量来避免许多问题,但这样做会影响可读性。与var不同,let只是一个声明的开始,而不是一个完整的表达式。这意味着您不能将单个let声明作为代码块的主体(这是有道理的,因为声明的变量无法访问)。实践:Scopingrulelet声明的变量作用域只在声明它的块或子块内部,类似于var。两者的主要区别是var声明的变量作用域是整个封闭函数。//eg1:functionvarTest(){varx=1;{变量x=2;//相同的变量!控制台日志(x);//2}console.log(x);//2}functionletTest(){让x=1;{让x=2;//不同的变量console.log(x);//2}console.log(x);//1}函数constTest(){consta=1;{consta=2console.log(a)//同let声明}console.log(a)//1}varTest()letTest()constTest()//console:>2>2>2>1>2>1在程序和函数的顶层,let与var不同,它不会在全局对象上创建属性。在全局范围内,let不同于var,它不会在全局对象上创建属性varx="global";lety="global";console.log(this.x);//“全局”console.log(this.y);//undefined在同一个函数或块作用域中重复声明变量将抛出SyntaxErrorif(x){letfoo;让foo;//SyntaxErrorthrown.}这个错误在switch语句中也会被触发,因为是同一个块作用域。letx=1;switch(x){案例0:letfoo;休息;情况1:让foo;//SyntaxErrorforredeclaration.break;}嵌套在case子句中的块创建了一个新的块操作域词法环境,在上诉重复声明时不会出现错误。letx=1;switch(x){案例0:{letfoo;休息;}案例1:{让foo;休息;}}Temporaldeadzone,TDZ(临时死区)从一个代码块的开始,直到代码执行到声明变量的那一行之前,let或const声明的变量处于“临时死区”。当变量处于临时死区,还没有初始化,尝试访问该变量时会抛出ReferenceError。当代码执行到声明变量的行时,变量被初始化为一个值。如果在声明中没有指定初始值,变量将被初始化为未定义。与使用var声明的变量不同,如果变量在声明之前被访问,则该变量将返回undefined。以下代码演示了在使用let和var声明变量的行之前访问变量的不同结果。{//TDZ从作用域的开头开始console.log(bar);//未定义的console.log(foo);//引用错误varbar=1;让foo=2;//EndofTDZ(forfoo)}暂时让死区(TDZ),const声明的变量从一个代码块(blockscope)执行到声明前的状态。从var关键字的角度来看,TDZ是因为语句执行的先后顺序而产生的。var有变量提升,即无论var在哪里定义,定义语句都会提升到var作用域(函数块或执行上下文)开始执行(变量提升),所以从代码块到let,在const语句声明之前,声明的变量处于临时死区文档说明:使用术语“temporal”是因为该区域取决于执行的顺序(时间)而不是代码编写的顺序(位置).例如,下面的代码之所以有效,是因为即使使用let变量的函数出现在变量声明之前,该函数也是在TDZ之外调用的。使用术语“时间”是因为区域取决于执行顺序(时间),而不是代码编写的顺序(位置)。例如,下面的代码之所以有效,是因为即使使用let变量的函数出现在变量声明之前,函数的执行也在时间死区之外。{//TDZ从作用域开始。TDZ从作用域开始(块作用域)constfunc=()=>console.log(letVar);//OK//在TDZ内letVar访问抛出`ReferenceError`letletVar=3;//TDZ结束(对于letVar)。letVarTDZ结束func();//CalledoutsideTDZ!}因为外部变量foo有一个值,所以if语句块将被执行,但是由于词法作用域,这个值在块内不可用:if块内的标识符foo被letfoo。表达式(foo+55)抛出ReferenceError异常是因为letfoo还没有完成初始化,它还处于临时死区。函数测试(){varfoo=33;如果(foo){让傻瓜=(foo+55);//ReferenceErrorconsole.log(fool,foo)//让foo='a'}}test();else大小写用于块级作用域,其中let将变量的作用域限制在一个块内,而var声明一个作用域在函数内的变量。vara=1;varb=2;if(a===1){vara=11;//作用域是全局的letb=22;//范围在if块内console.log(a);//11控制台日志(b);//22}控制台日志(a);//11console.log(b);//2但是,声明var和let组合的方式会抛出SyntaxError,因为var将变量提升到块的顶部,这导致变量的隐式双重声明。让x=1;{变量x=2;//SyntaxErrorforre-declaration}keyPointsblock-levellocalvariables就像const一样,let在全局声明时(在最顶层作用域中)不会创建window对象的属性。tidyletvarconstscope块级作用域执行上下文或函数作用域(var语句用于声明函数作用域或全局作用域的变量)全局或局部声明的块声明的变量值特征可变值变量可变变量的值是常量,不能改变(初始化必须指定一个价值)。在变量声明语句的范围内重复声明相同的变量/常量。可重复声明可以重复。不可重复。参考资料:MDN