简介
ES6是JavaScript语言的一次重大更新,于2015年6月正式发布。它的目标是利用Javascript可以构建复杂的应用程序。
各大浏览器推出的最新版本已经对ES6有了更高的支持度,实际的支持情况可以查看kangax.github.io/es5-compat-table/es6/, 如果你不放心你的代码是否可以在所有的浏览器上运行,可以使用Babel转码器将ES6转为ES5的代码。
语法
本文的示例代码使用ES6,你可以利用ES6Fiddle,或者Babel转码器命令行工具来运行代码。
块作用域声明
在Javascript中,作用域是function
范围内的。如果你需要一个块作用域,最常用的方式就是使用IIFE(立即执行函数)。例如:
1 | var a = 2; |
let
声明
有了ES6,现在我们可以创建块作用域。我们不要 var
标识符,取而代之的是 let
标识符:
1 | var a = 2; |
这是一个定义块作用域最好的方式,利用 {...}
将作用域括起来, 建议将所有的变量声明放在最顶端,例如:
1 | { |
这是一个良好的编码习惯。
有另外一种let
声明的实验形式(不是标准形式),叫做 let-块,是这样的:
1 | let (a = 2, b, c) { |
这种声明形式更加的清晰,对比上面的两种形式,它们是十分相似的。不幸的是ES6标准采用了上面这种形式,而不是下面这种更加清晰的清晰的方案。
为了说明 let ..
声明的implicit,考虑下面这种使用方法:
1 | let a = 2; |
哪些变量仅仅在 if
语句中存在,哪些变量在for
语句中存在?
答案是: if
语句包含了a
和b
, for
语句包含了i
和 j
。
我们再看一种情况,如果let
的声明太晚会引起一些错误。不像var
会有声明的提升:
1 | { |
执行console.log(b)
时会有个错误,因为你调用了一个还没有被初始化的变量。变量b
在作用域内已经被声明了,但是直到 let b
语句执行之前, 变量b
没有被初始化,在这之前想要获取b
的值会引发一个错误。注意:转化为ES5的代码,并不会引发这个错误。
let
+ for
考虑:
1 | var funcs = []; |
let i
语句为循环的每一次迭代重新定义了一个新的 i
。 这意味在循环内部创建了一个闭包。
如果你使用 var i
,最后输出的结果是5而不是3, 这是因为作用域内仅仅一个变量 i
被闭包闭合,而不是每一次都有一个新的变量 i
。
可以通过下面的代码,实现相同的效果:
1 | var funcs = []; |
在上面的代码中我们每次都创建一个新的变量j,所以和前面的代码有相同的原理。
const
声明
有另外一种块作用域声明方式:const
用来创建常量。
常量是初始化后read-only的变量。
1 | { |
常量并不是对值的限制,而是对变量赋值的限制。const
并不是让变量的值不能变,而是让变量不能够被赋值。如果值是一个数组或者一个对象,值的内容是可以被修改的:
1 | { |
变量 a
并不是一个常数组,而是它有一个到这数组的常量引用,这个数组是可变的。
const
or not
有传闻说JS引擎能够对 const
进行优化, 相对于这一点,更重要的是你是否需要一个常量值。
所以建议仅仅在你需要显示表明这个值不可变的情况下使用 const
, 而不是依赖 const
对代码的效率进行优化。
块作用域中的函数
考虑如下代码:
1 | { |
foo()
函数在块作用域中声明,多以无法在作用域外被调用。需要注意的是,在作用域内,像以前一样,函数声明具有声明提升的效果。
像下面这样的代码就会有问题:
1 | if (something) { |
在之前的ES环境中,不管something的值,运行结果是2。因为函数声明的提升效果,而且往往后面的声明会战胜前面的声明。
在ES6中,会得到一个引用错误。
总结
在ES6中可以使用 let
, const
得到块作用域,在作用域中声明的变量,作用域之外无法访问。并且,函数的声明也是块作用域,在作用域内, let
的声明没有变量提升的效果,函数的声明仍旧有提升的效果。