本章涉及3个知识点,var、let、const,现在让我们了解一下这3个关键字的特点和使用方法。在varJavaScript中,我们通常所说的作用域就是函数作用域。使用var声明的变量,无论在代码中的何处声明,都会被提升到当前作用域的顶部。这种行为称为变量提升(Hoisting)。也就是说,如果在函数内部声明了一个变量,它会被提升到函数的开头,而全局声明的变量会被提升到全局作用域的顶部。functiontest(){console.log('1:',a)//undefinedif(false){vara=1}console.log('3:',a)//undefined}当test()实际上是执行后,上面代码中的变量a会被提升到函数的顶层声明,即使if语句的条件为假,也不会影响变量a的提升。functiontest(){vara//语句未赋值console.log('1:',a)//undefinedif(false){a=1}//语句未赋值console.log('3:',a)//undefined}在函数嵌套的场景下,变量只会被提升到最近函数的顶部,不会。//b被提升到函数a的顶部,但不是函数测试。functiontest(){functiona(){if(false){varb=2}}console.log('b:',b)}test()//bisnotdefined如果a没有声明,那么它will报错和没有语句,语句后不赋值是不一样的。这个一定要区分,才能帮助我们找到bug。//aisnotdeclaredaisnotdefinedlet和const可以声明块级作用域,用法和var类似,let的特点是不会提升变量,而是锁定在当前块。一个很简单的例子:functiontest(){if(true){console.log(a)//TDZ,俗称临时死区,用来描述变量没有提升的现象leta=1}}test()//aisnotdefinedfunctiontest(){if(true){leta=1}console.log(a)}test()//aisnotdefined唯一正确的使用方式:先声明,再访问.functiontest(){if(true){leta=1console.log(a)}}test()//1const声明一个常量,一旦声明就不能改变,必须对常量进行初始化赋值。consttype="ACTION"让我们尝试重新声明类型,看看会报什么错误:consttype="ACTION"type=1console.log(type)//"type"isread-onlyconsttype="ACTION"lettype=1console.log(type)//Duplicatedeclaration"type"const是一个常量,默认赋值是不允许修改的,但是如果定义了对象Object,则可以修改对象内部的属性值。consttype={a:1}type.a=2//允许修改type.a的属性值,而不是直接修改type的值。console.log(type)//{a:2}const和let的相同点和不同点是一样的:const和let在当前块内有效,在块外执行时会被销毁,没有变量提升(TDZ),声明不能重复。区别:const不能再赋值,let声明的变量可以重复赋值。临时死区(TDZ)我们上面也提到了TDZ场景,那么有什么用呢?答案是它不起作用。临时死区是指在当前作用域的块中,声明变量之前的区域称为临时死区。if(true){//这个区域是TDZleta=1}块级作用域的使用场景除了上面提到的常用声明方式外,我们还可以在循环中使用。最著名的面试题:inalooptimerclosure的测试题在for循环中使用var声明的循环变量,会跳出循环体污染当前函数。for(vari=0;i<5;i++){setTimeout(()=>{console.log(i)//5,5,5,5,5},0)}console.log(i)//5i跳出循环体,污染外部函数//将var改成letfor(leti=0;i<5;i++){setTimeout(()=>{console.log(i)//0,1,2,3,4},0)}console.log(i)//iisnotdefinedicannotpollutionexternalfunctions分析经典闭包setTimeout面试题中的执行顺序DeclareintheglobalscopeIf你在全局范围内使用let或const声明,声明的变量本身就是一个全局属性,比如closed。只会覆盖该全局变量,而不会替换它。window.closed=falseletclosed=trueclosed//truewindow.closed//false最佳实践在实际开发中,我们选择使用var、let还是const,取决于我们的变量是否需要更新,通常我们希望变量保证不更新被恶意修改,却大量使用const。在react中,props传递的对象是不能改变的,所以要用const声明。声明对象时,也推荐使用const。当需要修改声明的变量值时,使用let,所有可以使用var的场景都可以用let代替。=>返回文章目录
