ECMAScript变量是松散类型的,这意味着变量可以用来保存任何类型的数据。每个变量只不过是命令的占位符,用于保存任意值。在ECMAScript6之前,变量是使用var关键字声明的,ECMAScript6增加了const和let关键字来声明变量。var使用var关键字来声明变量:varmsg;//未初始化时,变量持有一个特殊值undefinedvarmsg="Hello";//初始化msg=3.14;//可以改变保存的值和值类型,但不能改变Recommendedscopevar声明的变量的作用域是函数作用域,函数退出时变量被销毁:functiontest(){varmsg="Hello";}test();console.log(msg);//ReferenceError:msg未定义但省略var将创建一个全局变量:functiontest(){msg="Hello";}test();console.log(msg);//你好但是这个操作会让全局变量难以维护,不推荐这样。vardeclarationhoisting在var声明之前调用变量不会报错,因为var声明的变量会自动提升到函数作用域的顶部:functiontest(){console.log(name);varname="小明";}test();//undefinedletlet与var做同样的事情,但有一个非常重要的区别。主要区别在于:let在块范围内声明变量,而var在函数范围内声明变量。函数varScope(){if(true){varname="varname";控制台日志(名称);//变量名}console.log(name);//varname}functionletScope(){if(true){letname="letname";控制台日志(名称);//让名字}console.log(name);//ReferenceError:nameisnotdefined}从上面的例子中,我们知道let关键字声明变量的作用域只在块内。块作用域是函数作用域的子集,适用于var的相同作用域限制也适用于let。let的重复声明不允许在同一块范围内重复声明。出现时会报错:functionvarScope(){varname="varname";varname="varname";}functionletScope(){letname="letname";让名字=“让名字”;//SyntaxError:Identifier'name'hasalreadybeendeclared}但是,嵌套相同的标识符相当于新建一个块作用域,所以相同的标识符不会报错,因为在同一个块中没有重复声明:functionletScope(){让名字="让名字1";if(true){让名字="让名字2";控制台日志(名称);//让名字2}console.log(name);//letname1}临时死区var声明变量的初始值未定义。然而,与let不同的是,与var不同,用let声明的变量不会提升到作用域中。在执行声明之前,它不会被初始化。在初始化之前访问变量将导致ReferenceError。let声明变量之前的执行时刻称为“临时死区”。let和var的另一个重要区别是let声明的变量不会在作用域内被提升。函数deadZone(){console.log(varname);//未定义的console.log(letname);//ReferenceErrorletletname="letname";varvarname="varname";}globaldeclarationvaringlobalscope用let声明的变量成为window对象的属性;用let声明的变量不会成为window对象的属性。varvarname='varname';console.log(window.name);//'varname'letletname="letname";console.log(window.letname);//undefined但let声明仍然在全局范围内发生,对应的变量会一直存在于页面的声明周期中。因此,为了避免SyntaxError,必须保证页面没有重复声明同一个变量。constconst声明的变量也是块作用域,和let基本一样,只是在const声明变量的时候必须同时初始化变量。声明变量的值是只读的,修改const声明变量将导致运行时错误。//声明一个常量必须有一个初始值constname;//语法错误:const声明中缺少初始值设定项//块作用域constname="constname1";if(true){constname="constname2";控制台.log(名称);//常量名称2}console.log(name);//常量名称1name="常量名称2";//TypeError:赋值给常量变量。//尝试重新声明constname="constname3";//SyntaxError:Identifier'name'hasalreadybeendeclaredconst对象和数组也可以被声明。当声明的变量是对象时,不修改对象引用,而是修改对象内部的属性,不违反const限制。conststudent={};student.name="小明";const其实保存的不是变量的值不能改变,而是变量指向的内存地址不能改变。for循环中不能使用const声明变量,因为变量在迭代过程中会自增,会抛出TypeError错误:for(consti=0;i<10;i++){}//TypeError:Assignment到常量变量。但是,在for-in或for-of循环中使用时不会报错。for(constkeyin{name:"小明",age:24}){console.log(key);//name,age}for(constvalueof["name","age","id","sex"]){console.log(value);//name,age,id,sex}总结var声明变量带来了很多问题,ECMAScript6加入的let和const为语言提供了更精确的声明范围和语义更好的支持,提高了代码质量。新增两个关键字后,不再需要用var来声明变量,让变量有明确的作用域、声明位置和不变的值。但是在声明变量的时候最好使用const,这样在浏览器运行的时候变量就强制保持不变。仅当您事先知道将来会有更改时才使用let。更多内容请关注公众号《海人的故事》
