1.历史
ES6全程ECMAScript 6,参考书籍:ECMAScript 6入门 作者:阮一峰
在有js基础上,更好的理解ES6.
1996年11月,Netscape公司创造了Javascript,次年,被国际标准化组织(ECMA)定为国际标准。
该标准针对JavaScript,为避免版权冲突,这个标准被命名为ECMAScript,简称ES.
随着版本更替,2015年的ES2015做出了大幅度的改变,开始制定ES6规则,象征着新标准的改变,此后,ES6不仅仅表示了2015年的ES2015标准,也代表了“下一代JavaScript语言”。
2.配置
1)Babel转码器
Babel可以将ES6代码转化为ES5代码,从而支持老版本浏览器的执行。
例如:ES6标准写法:input.map(item => item + 1);通过Bable转码后:input.map(function (item) { return item + 1; });
上述 => 的写法就是ES6写法,代替了函数返回。
2)polyfill
Babel默认只转换新的JS语法,而不转换新的API。比如ES6中新的API:Set,Map,Proxy,Aymbol等全局对象。需要安装core-js
和regenerator-runtime为当前环境提供一个垫片。
但是需要注意一点,网页实时将ES6转换为ES5对性能会有影响。因此,生产环境需要加载已经转完码的脚本。
3.新语法
1)let命令
ES6新增的let命令类似于var,区别的是,var是全局变量,一处定义,全局有效。但let的语法只在代码块,作用域内有效,而且,只能先定义后使用。对于同一变量,let不允许重复定义,但var却可以。例如:
{ let a = 10; var b = 10; } alert(a); //错误,a只能在上面{}的作用域内有效 alert(b); //正确,var全局有效
例如2:
{ alert(a); //错误,a是下面的let定义的变量,let定义的变量只能在他后面使用,在定义前使用是错误的,在这定义前的区域称为死区。 alert(b); //正确,var全局有效,不分定义先后顺序。这种不分顺序的原因其实是种“变量提升”现象,即变量可以在声明之前使用。 let a = 10; var b = 10; }
那么,为什么要有let这个语法呢,var多方便啊,随便用的。正因随便二字使得var没有规范,可能使用的变量不知道在哪里已经定义过了,我们因该遵循哪里要用,那里定义,别处不能使用的原则,例如:
for循环中,使用let就很合适
for( let i = 0; i < 10; i ++){ console.log(i); }
这里很明显,我定义的i变量只希望用在for循环里面,除了for循环我用不到,也不希望别人误用,let定义的变量就比var好多了。
2)块级作用域
其实在上述中已经有提到块级作用域了{},块级作用域就是为了避免一处定义全局可用的现象,我明明只希望在for循环中使用这个变量,结果for循环外你也能使用了,这不是泄露了我的变量了吗,再说,如果我定义完了变量,你在后面又重复定义了我的变量,这不是改变了我的变量了吗,这不乱套了。比如:
var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = 'hello world'; } } f(); // undefined
上面代码的原意是,if
代码块的外部使用外层的tmp
变量,内部使用内层的tmp
变量。但是,函数f
执行后,输出结果为undefined
,原因在于变量提升,导致内层的tmp
变量覆盖了外层的tmp
变量。
块级作用域的用法:
function f1() { let n = 5; if (true) { let n = 10; } console.log(n); // 5 }
上面的函数有两个代码块,都声明了变量n
,运行后输出 5。这表示外层代码块不受内层代码块的影响。如果两次都使用var
定义变量n
,最后输出的值才是 10。
上面是变量的作用域,函数也是一样的,但这里有一个很大的不同:
function f() { console.log('I am outside!'); } (function () { if (false) { // 重复声明一次函数f function f() { console.log('I am inside!'); } } f(); }());
上面代码在 ES5 中运行,会得到“I am inside!”,因为在if
内声明的函数f
会被提升到函数头部。
ES6 就完全不一样了,理论上会得到“I am outside!”。因为块级作用域内声明的函数类似于let
,对作用域之外没有影响。但是,如果你真的在 ES6 浏览器中运行一下上面的代码,是会报错的。
原来,如果改变了块级作用域内声明的函数的处理规则,显然会对老代码产生很大影响。为了减轻因此产生的不兼容问题,ES6 在附录 B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式:
- 允许在块级作用域内声明函数。
- 函数声明类似于
var
,即会提升到全局作用域或函数作用域的头部。 - 同时,函数声明还会提升到所在的块级作用域的头部。
因此,考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
// 块级作用域内部的函数声明语句,建议不要使用 { let a = 'secret'; function f() { return a; } } // 块级作用域内部,优先使用函数表达式 { let a = 'secret'; let f = function () { return a; }; }
另外需要注意的是,ES6使用{}表示块级作用域的,如果没有{}会认为不存在块级作用域,这时使用let会报错,因为找不到作用域。