ES6 中的部分新特性
on Front-End
let
关键字
ES6
新增了 let
关键字用来声明变量。用法类似于 var
,但是所声明的变量只在 let
所在的代码块内有效。for
循环的计数器就非常合适使用 let
,这样计数器 i
只在 for
循环体内有效,在循环体外引用就会报错。
没有变量提升:
let
所声明的变量一定要在声明后使用,否则会报错。封闭作用域:只要块级作用域内存在
let
命令,这个区块里其声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量都会报错。注意:这里的报错是不是指报出undefined
,而是指ReferenceError
。所以即使使用typeof
都不再是一个百分之百安全的操作。这样的设计是为了让人们养成良好的编程习惯,变量一定要在声明之后使用,否则就报错。不允许重复声明:不允许在相同作用域内重复声明同一个变量。
定义的全局变量不再是顶层对象的属性。
const
关键字
声明一个只读的常量,一旦声明,该常量的值就不能改变。这意味着,用 const
一旦声明变量,就必须立即初始化,不能留到以后赋值。const
的其他限制同上面的 let
关键字。
const
实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。因此,将一个对象声明为常量必须非常小心。如果真的想将对象冻结,应该使用 Object.freeze
方法。
块级作用域
ES5
只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。比如说,内层变量可能会覆盖外层变量,用来计数的临时的循环变量容易泄露为全局变量等等。而 ES6
允许块级作用域(用 {}
包裹的代码区域)的任意嵌套,外层作用域无法读取内层作用域的变量,内层作用域依然可以定义外层作用域的同名变量。
- 允许在块级作用域之中可以声明函数。块级作用域之中,函数声明语句的行为类似于
let
,在块级作用域之外不可引用,且声明时没有变量提升。所以应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
do
表达式
本质上,块级作用域是一组语句,将多个操作封装在一起,没有返回值。
而在块级作用域之前加上 do
就可以使它变为 do
表达式,然后就会返回内部最后执行的表达式的值。下面的例子中,变量 x
会得到整个块级作用域的返回值 w * w + h
。
let x = do {
let w = 23, h = 8;
w * w + h;
};
箭头函数
Module
模块
在 ES6
之前出现过一些模块加载方案,代表的有 CommonJS
和 AMD
两种。前者用于服务器,后者用于浏览器。ES6
在语言标准的层面上实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS
和 AMD
规范,成为浏览器和服务器通用的模块解决方案。
ES6
模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS
和 AMD
模块都只能在运行时确定这些东西。因为只有运行时才能得到要加载的对象,导致完全没办法在编译时做到静态优化。
ES6
模块不是对象,而是通过 export
命令显式指定输出的代码,再通过 import
命令输入。ES6
可以在编译时就完成模块加载,效率要比 CommonJS
模块的加载方式高。当然,这也导致了没法引用 ES6
模块本身,因为它不是对象。
除了静态加载带来的各种好处,ES6
模块还有以下好处:
不再需要
UMD
模块格式了,将来服务器和浏览器都会支持ES6
模块格式。目前各种工具库已经做到了这一点。将来浏览器的新
API
可以用模块格式提供,不再必须做成全局变量或者navigator
对象的属性。不再需要对象作为命名空间(比如
Math
对象),未来这些功能可以通过模块提供。
ES6
模块自动采用严格模式,不管有没有在模块头部加上 "use strict";
。其中尤其需要注意 this
的限制:ES6
模块之中顶层的 this
指向 undefined
,即不应该在顶层代码使用 this
。