ES6JavaScript新特性ES6:JavaScript新特性分类:JavaScriptNode.jsJSEngineJavaScript引擎2014-05-1911:441727人阅读评论(0)收藏举报目录(?)[+]我相信,在ECMAScript.next到来的时候,我们现在每天都在写的JavaScript代码将会发生巨大的变化.接下来的一年将会是令JavaScript开发者们兴奋的一年,越来越多的特性提案将被最终敲定,新一版本的JavaScript将会慢慢得到普及.本文中,我将会讲几个我个人很期待的,希望能在2013年或者更晚一点使用上的新特性.ES.next目前的实现情况可以通过查看JuriyZaytsev总结的ECMAScript6兼容性表格,和Mozilla的ES6实现情况页面以及通过使用现代浏览器的最新版本(比如ChromeCanary,FirefoxAurora),来了解目前有哪些已经实现了的ES.next特性.在Canary中,记得要进入chrome:flags打开'启用实验性JavaScript'选项以激活所有最新的的JavaScript特性.另外,许多ES.next特性还可以通过使用Google的Traceur转换编译器(这里有一些单元测试的例子)来体验,以及一些shim项目比如ES6-Shim和HarmonyCollections,也实现了不少新特性.在Node.js(V8)中使用--harmony命令行选项可以开启一些试验性质的ES.next特性,包括块级作用域,WeakMap等等.模块我们已经习惯了将我们的代码分割成为更加便于管理的功能块.在ES.next中,一个模块(module)是就是一个module声明,以及包含在该声明中的一组代码.模块可以用内联方式(inline)声明,也可以引入一个外部的模块文件.一个名为Car的内联模块的写法大致如下:moduleCar{//导入…//导出…}一个模块实例就是一个被求过值的模块,它已经被链接到了其他的模块身上或者已经有了词法上的封装数据.下面是一个模块实例的例子:modulemyCaratcar.js;module声明可以使用在如下上下文中:moduleUniverseTest{};moduleUniverse{moduleMilkyWay{}};moduleMilkyWay='Universe/MilkyWay';moduleSolarSystem=Universe.MilkyWay.SolarSystem;moduleMySystem=SolarSystem;一个export声明声明了一个可以被其他模块看到的局部函数或变量.moduleCar{//内部变量varlicensePlateNo='556-343';//暴露到外部的变量和函数exportfunctiondrive(speed,direction){console.log('details:',speed,direction);}exportmoduleengine{exportfunctioncheck(){}}exportvarmiles=5000;exportvarcolor='silver';};一个模块可以使用import导入任何它所需要的其他模块.导入模块会读取被导入模块的所有可导出数据(比如上面的drive(),miles等),但不能修改它们.导出的变量或函数可以被重命名.再次用到上面导出相关的例子,我们现在可以有选择性的导入一些模块中的功能.比如我们可以导入drive():importdrivefromCar;还可以可以同时导入drive()和miles:import{drive,miles}fromCar;下面,我们要讲一下模块加载器API的概念.模块加载器能够让我们动态的加载所需要的脚本.类似于import,我们可以使用被导入模块中的所有用export声明过的东西.//Signature:load(moduleURL,callback,errorCallback)Loader.load('car.js',function(car){console.log(car.drive(500,'north'));},function(err){console.log('Error:'+err);});load()接受三个参数:moduleURL:表示一个模块URL的字符串(比如car.js)callback:一个回调函数,接受模块加载,编译,以及执行后的输出结果errorCallback:一个回调函数,在加载或编译期间发生错误时调用关于类(class)我不打算在本文中过多的讲ES.next中的类,如果你想知道类和模块将会有什么联系,AlexRussell曾经写过一个很好的例子来说明这件事.JavaScript中有了类,并不意味着要把JavaScript变成Java.ES.next中的类只是我们已经熟悉的语义(比如函数,原型)的另外一种声明方式下面是用来定义一个widget的ES.next代码:modulewidgets{//...classDropDownButtonextendsWidget{constructor(attributes){super(attributes);this.buildUI();}buildUI(){this.domNode.onclick=function(){//...};}}}下面是去糖(de-sugared)后的做法,也就是我们目前正在使用的方法:varwidgets=(function(global){//...functionDropDownButton(attributes){Widget.call(this,attributes);this.buildUI();}DropDownButton.prototype=Object.create(Widget.prototype,{constructor:{value:DropDownButton},buildUI:{value:function(e){this.domNode.onclick=function(e){//...}}}});})(this);ES.next的写法的确让代码变的更可读.这里的class也就相当于是function,至少是做了目前我们用function来做的一件事.如果你已经习惯并且也喜欢用JavaScript中的函数和原型,这种未来的语法糖也就不用在意了.这些模块如何和AMD配合使用?ES.next中的模块是朝着正确的方向走了一步吗?也许是吧.我自己的看法是:看相关的规范文档是一码事,实际上使用起来又是另一码事.在Harmonizr,RequireHM和Traceur中可以体验新的模块语法,你会非常容易的熟悉这些语法,该语法可能会觉得有点像Python的感觉(比如import语句).我认为,如果一些功能有足够广泛的使用需求(比如模块),那么平台(也就是浏览器)就应该原生支持它们.而且,并不是只有我一个人这么觉得.JamesBurke,发明了AMD和RequireJS的人,也曾经说过:我想,AMD和RequireJS应该被淘汰了.它们的确解决了一个实际存在的问题,但更理想的情况是,语言和运行环境应该内置类似的功能.模块的原生支持应该能够覆盖RequireJS80%的使用需求,从这一点上说,我们不再需要使用任何用户态(userland)的模块加载库了,至少在浏览器中是这样.不过James的质疑是ES.next的模块是否是一个足够好的解决方案,他曾在六月份谈到过自己关于ES.next中模块的一些想法ES6Modules:Suggestionsforimprovement以及再后来的一篇文章WhynotAMD?.IsaacSchlueter前段时间也写过一些自己的想法,讲到了ES6的模块有哪些不足.尝试一下下面这些选项,看看你的想法如何.兼容目前引擎的Module实现TraceurdemoHarmonizrRequireHMES6ModuleLoaderObject.observe()通过Object.observe,我们可以观察指定的对象,并且在该对象被修改时得到通知.这种修改操作包括属性的添加,更新,删除以及重新配置.属性观察是我们经常会在MVC框架中看到的行为,它是数据绑定的一个重要组件,AngularJS和Ember.js都有自己的解决方案.这是一个非常重要的新功能,它不仅比目前所有框架的同类实现性能要好,而且还能更容易的观察纯原生对象.//一个简单的对象可以作为一个模块来使用vartodoModel={label:'Default',completed:false};//我们观察这个对象Object.observe(todoModel,function(changes){changes.forEach(function(change,i){console.log(change);/*哪个属性被改变了?change.name改变类型是什么?change.type新的属性值是什么?change.object[change.name]*/});});//使用时:todoModel.label='Buysomemoremilk';/*label属性被改变了改变类型是属性值更新当前属性值为'Buysomemoremilk'*/todoModel.completeBy='01/01/2013';/*completeBy属性被改变了改变类型是属性被添加当前属性值为'01/01/2013'*/deletetodoModel.completed;/*completed属性被改变了改变类型是属性被删除当前属性值为undefined*/Object.observe马上将会在ChromeCanary中实现(需要开启启用实验性JavaScript选项).兼容目前引擎的Object.observe()实现Chromium特殊版本Watch.JS可以实现类似的功能,但它并不是实现Object.observe的polyfill或shimRickWaldron的这篇文章有关于Object.observe更详细的介绍.译者注:Firefox很早就有了一个类似的东西:Object.prototype.watch.默认参数值默认参数值(Defaultparametervalues)的作用是:在一些形参没有被显式传值的情况下,使用默认的初始化值来进行初始化.这就意味着我们不再需要写类似options=options||{};这样的语句了.该语法形式就是把一个初始值赋值给对应的形参名:functionaddTodo(caption='Dosomething'){console.log(caption);}addTodo();//Dosomething拥有默认参数值的形参只能放在形参列表的最右边:functionaddTodo(caption,order=4){}functionaddTodo(caption='Dosomething',order=4){}functionaddTodo(caption,order=10,other=this){}已经实现该特性的浏览器:Firefox18+译者注:Firefox15就已经实现了默认参数值,作者所说的18只是说18支持,并不是说18是第一个支持的版本.包括本文下面将要提到的chrome24+等等,都有这个问题.块级作用域块级作用域引入了两种新的声明形式,可以用它们定义一个只存在于某个语句块中的变量或常量.这两种新的声明关键字为:let:语法上非常类似于var,但定义的变量只存在于当前的语句块中const:和let类似,但声明的是一个只读的常量使用let代替var可以更容易的定义一个只在某个语句块中存在的局部变量,而不用担心它和函数体中其他部分的同名变量有冲突.在let语句内部用var声明的变量和在let语句外部用var声明的变量没什么差别