- let和const命令:
Es6新增了let命令,声明变量,但与var不一样的,只在let命令所在的代码块内有效(如for循环之外let声明的变量就不再有效)。并且let不像var那样会发生“变量提升”现象,所以,变量一定要在声明后使用,否则报错。
-
暂时性死区; 只要块级作用域内存在let命令,它所声明的变量就“绑定”binding这个区域,不再受外部的影响。
注意: es6明确规定:如果区块中存在let和const命令,这个区块会对这些命令声明的变量,从一开始就形成了封闭作用域,凡是在这些声明之前就使用的就会报错。总之,在代码区块内,使用let命令声明变量之前,该变量都是不可用的,这在语法上,成为“暂时性死区”。也就意味着typeof不再是一个百分之百安全的操作。作为比较,如果一个变量根本没有被声明,使用
typeof
反而不会报错。总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。 if (true) {
// 暂时性死区开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError let tmp; // 暂时性死区结束
console.log(tmp); // undefined tmp = 123;
console.log(tmp); //
}-
let不允许重复声明。
function a() {
let b;
b=2; let b;//----语法错误
} 块级作用域:在没有块级作用域的时候,会出现内层变量覆盖外层以及用来计数的循环变量会泄露为全局变量。而let实际为JavaScript新增了块级作用域。允许作用域的任意嵌套,外层作用域也不受内层代码块的影响,这样也使得获得广泛应用的立即执行匿名函数不再必要了。
-
块级作用域与函数声明: es6引入块级作用域,明确允许在块级作用域之中声明函数,并且,其语法行为类似于let,在块级作用域之外不可引用。
考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
另外,还有一个需要注意的地方。ES6的块级作用域允许声明函数的规则,只在使用大括号的情况下if( condition){大括号里的函数}成立,如果没有使用大括号,就会报错。
-
const声明一个只读常量,一旦声明,常量的值就不能改变。也就是,声明了就必须立即初始化。
与let命令相同,只在声明所在的块级作用域内有效,也不提升,存在暂时性死区,只能在声明位置之后使用。也不可重复声明。
注意的是:对于复合型的变量,指向的是地址,const只是保证变量名指向的地址不变,并不保证该地址的数据不变。例如const定义的数组和对象等,可以使用push等,但不能重新赋值。如果想把对象冻结,应该使用object.freeze()方法。除了将对象本身冻结,对象的属性也应该冻结。
-
顶层对象的属性:浏览器环境指的是window对象,node指的是global对象,在ES5之后,顶层对象的属性与全局变量是等价的。
ES6为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从ES6开始,全局变量将逐步与顶层对象的属性脱钩。
-
顶层对象: window或者global,同一段代码为了能够在各种环境中都嫩取到顶层对象,现在一般都是用this变量,但是有局限性。
现有提案,建议将global作为顶层对象,垫片库system.global模拟了这个提案,在所有环境中拿到global