ECMAScript 6(如下簡稱ES6)是JavaScript語言的下一代標準,已經在2015年6月正式發佈了。它的目標,是使得JavaScript語言能夠用來編寫複雜的大型應用程序,成爲企業級開發語言。javascript
標準的制定者有計劃,之後每一年發佈一次標準,使用年份做爲標準的版本。由於當前版本的ES6是在2015年發佈的,因此又稱ECMAScript 2015。也就是說,ES6就是ES2015,下一年應該會發布小幅修訂的ES2016。html
一個常見的問題是,ECMAScript和JavaScript究竟是什麼關係?java
要講清楚這個問題,須要回顧歷史。1996年11月,JavaScript的創造者Netscape公司,決定將JavaScript提交給國際標準化組織ECMA,但願這種語言可以成爲國際標準。次年,ECMA發佈262號標準文件(ECMA-262)的初版,規定了瀏覽器腳本語言的標準,並將這種語言稱爲ECMAScript,這個版本就是1.0版。node
該標準從一開始就是針對JavaScript語言制定的,可是之因此不叫JavaScript,有兩個緣由。一是商標,Java是Sun公司的商標,根據受權協議,只有Netscape公司能夠合法地使用JavaScript這個名字,且JavaScript自己也已經被Netscape公司註冊爲商標。二是想體現這門語言的制定者是ECMA,不是Netscape,這樣有利於保證這門語言的開放性和中立性。react
所以,ECMAScript和JavaScript的關係是,前者是後者的規格,後者是前者的一種實現(另外的ECMAScript方言還有Jscript和ActionScript)。在平常場合,這兩個詞是能夠互換的。git
ES6從開始制定到最後發佈,整整用了15年。es6
前面提到,ECMAScript 1.0是1997年發佈的,接下來的兩年,連續發佈了ECMAScript 2.0(1998年6月)和ECMAScript 3.0(1999年12月)。3.0版是一個巨大的成功,在業界獲得普遍支持,成爲通行標準,奠基了JavaScript語言的基本語法,之後的版本徹底繼承。直到今天,初學者一開始學習JavaScript,其實就是在學3.0版的語法。github
2000年,ECMAScript 4.0開始醞釀。這個版本最後沒有經過,可是它的大部份內容被ES6繼承了。所以,ES6制定的起點實際上是2000年。npm
爲何ES4沒有經過呢?由於這個版本太激進了,對ES3作了完全升級,致使標準委員會的一些成員不肯意接受。ECMA的第39號技術專家委員會(Technical Committee 39,簡稱TC39)負責制訂ECMAScript標準,成員包括Microsoft、Mozilla、Google等大公司。json
2007年10月,ECMAScript 4.0版草案發布,原本預計次年8月發佈正式版本。可是,各方對因而否經過這個標準,發生了嚴重分歧。以Yahoo、Microsoft、Google爲首的大公司,反對JavaScript的大幅升級,主張小幅改動;以JavaScript創造者Brendan Eich爲首的Mozilla公司,則堅持當前的草案。
2008年7月,因爲對於下一個版本應該包括哪些功能,各方分歧太大,爭論過於激烈,ECMA開會決定,停止ECMAScript 4.0的開發,將其中涉及現有功能改善的一小部分,發佈爲ECMAScript 3.1,而將其餘激進的設想擴大範圍,放入之後的版本,因爲會議的氣氛,該版本的項目代號起名爲Harmony(和諧)。會後不久,ECMAScript 3.1就更名爲ECMAScript 5。
2009年12月,ECMAScript 5.0版正式發佈。Harmony項目則一分爲二,一些較爲可行的設想定名爲JavaScript.next繼續開發,後來演變成ECMAScript 6;一些不是很成熟的設想,則被視爲JavaScript.next.next,在更遠的未來再考慮推出。TC39委員會的整體考慮是,ES5與ES3基本保持兼容,較大的語法修正和新功能加入,將由JavaScript.next完成。當時,JavaScript.next指的是ES6,第六版發佈之後,就指ES7。TC39的判斷是,ES5會在2013年的年中成爲JavaScript開發的主流標準,並在此後五年中一直保持這個位置。
2011年6月,ECMAscript 5.1版發佈,而且成爲ISO國際標準(ISO/IEC 16262:2011)。
2013年3月,ECMAScript 6草案凍結,再也不添加新功能。新的功能設想將被放到ECMAScript 7。
2013年12月,ECMAScript 6草案發布。而後是12個月的討論期,聽取各方反饋。
2015年6月,ECMAScript 6正式經過,成爲國際標準。從2000年算起,這時已通過去了15年。
各大瀏覽器的最新版本,對ES6的支持能夠查看kangax.github.io/es5-compat-table/es6/。隨着時間的推移,支持度已經愈來愈高了,ES6的大部分特性都實現了。
Node.js是JavaScript語言的服務器運行環境,對ES6的支持度比瀏覽器更高。經過Node,能夠體驗更多ES6的特性。建議使用版本管理工具nvm,來安裝Node,由於能夠自由切換版本。不過,nvm
不支持Windows系統,若是你使用Windows系統,下面的操做能夠改用nvmw或nvm-windows代替。
安裝nvm須要打開命令行窗口,運行下面的命令。
$ curl -o https://raw.githubusercontent.com/creationix/nvm/<version number>/install.sh | bash
上面命令的version number
處,須要用版本號替換。本節寫做時的版本號是v0.29.0
。該命令運行後,nvm
會默認安裝在用戶主目錄的.nvm
子目錄。
而後,激活nvm
。
$ source ~/.nvm/nvm.sh
激活之後,安裝Node的最新版。
$ nvm install node
安裝完成後,切換到該版本。
$ nvm use node
使用下面的命令,能夠查看Node全部已經實現的ES6特性。
$ node --v8-options | grep harmony --harmony_typeof --harmony_scoping --harmony_modules --harmony_symbols --harmony_proxies --harmony_collections --harmony_observation --harmony_generators --harmony_iteration --harmony_numeric_literals --harmony_strings --harmony_arrays --harmony_maths --harmony
上面命令的輸出結果,會由於版本的不一樣而有所不一樣。
我寫了一個ES-Checker模塊,用來檢查各類運行環境對ES6的支持狀況。訪問ruanyf.github.io/es-checker,能夠看到您的瀏覽器支持ES6的程度。運行下面的命令,能夠查看本機支持ES6的程度。
$ npm install -g es-checker $ es-checker=========================================Passes 24 feature Dectations Your runtime supports 57% of ECMAScript 6=========================================
Babel是一個普遍使用的ES6轉碼器,能夠將ES6代碼轉爲ES5代碼,從而在瀏覽器或其餘環境執行。這意味着,你能夠用ES6的方式編寫程序,又不用擔憂現有環境是否支持。下面是一個例子。
// 轉碼前input.map(item => item + 1);// 轉碼後input.map(function (item) { return item + 1;});
上面的原始代碼用了箭頭函數,這個特性尚未獲得普遍支持,Babel將其轉爲普通函數,就能在現有的JavaScript環境執行了。
命令行下,Babel的安裝命令以下。
$ npm install --global babel-cli $ npm install --save babel-preset-es2015
而後在當前目錄下,新建一個配置文件.babelrc
。
// .babelrc{ "presets": ['es2015']}
Babel自帶一個babel-node
命令,提供支持ES6的REPL環境。它支持Node的REPL環境的全部功能,並且能夠直接運行ES6代碼。
$ babel-node>> console.log([1,2,3].map(x => x * x)) [ 1, 4, 9 ]>
babel-node
命令也能夠直接運行ES6腳本。假定將上面的代碼放入腳本文件es6.js
。
$ babel-node es6.js[1, 4, 9]
babel
命令能夠將ES6代碼轉爲ES5代碼。
$ babel es6.js"use strict";console.log([1, 2, 3].map(function (x) { return x * x;}));
-o
參數將轉換後的代碼,從標準輸出導入文件。
$ babel es6.js -o es5.js# 或者$ babel es6.js --out-file es5.js
-d
參數用於轉換整個目錄。
$ babel -d build-dir source-dir
注意,-d
參數後面跟的是輸出目錄。
若是但願生成source map文件,則要加上-s
參數。
$ babel -d build-dir source-dir -s
Babel也能夠用於瀏覽器。可是,從Babel 6.0開始,再也不直接提供瀏覽器版本,而是要用構建工具構建出來。若是你沒有或不想使用構建工具,只有經過安裝5.x版本的babel-core
模塊獲取。
$ npm install babel-core@5
運行上面的命令之後,就能夠在當前目錄的node_modules/babel-core/
子目錄裏面,找到babel
的瀏覽器版本browser.js
(未精簡)和browser.min.js
(已精簡)。
而後,將下面的代碼插入網頁。
<script src="node_modules/babel-core/browser.js"></script> <script type="text/babel"> // Your ES6 code </script>
上面代碼中,browser.js
是Babel提供的轉換器腳本,能夠在瀏覽器運行。用戶的ES6腳本放在script
標籤之中,可是要註明type="text/babel"
。
這種寫法是實時將ES6代碼轉爲ES5,對網頁性能會有影響。生產環境須要加載已經轉碼完成的腳本。
下面是Babel
配合Browserify
一塊兒使用,能夠生成瀏覽器可以直接加載的腳本。首先,安裝babelify
模塊。
$ npm install --save-dev babelify babel-preset-es2015
而後,再用命令行轉換ES6腳本。
$ browserify script.js -o bundle.js \ -t [ babelify --presets [ es2015 react ] ]
上面代碼將ES6腳本script.js
,轉爲bundle.js
,瀏覽器直接加載後者就能夠了。
在package.json
設置下面的代碼,就不用每次命令行都輸入參數了。
{ "browserify": { "transform": [["babelify", { "presets": ["es2015"] }]] }}
Node腳本之中,須要轉換ES6腳本,能夠像下面這樣寫。
先安裝babel-core
和babel-preset-es2015
。
$ npm install --save-dev babel-core babel-preset-es2015
而後,在項目根目錄下新建一個.babelrc
文件。
{ "presets": ["es2015"]}
而後在腳本中,調用babel-core
的transform
方法。
var es5Code = 'let x = n => n + 1';var es6Code = require('babel-core') .transform(es5Code, {presets: ['es2015']}) .code;// '"use strict";\n\nvar x = function x(n) {\n return n + 1;\n};'
上面代碼中,transform
方法的第一個參數是一個字符串,表示須要轉換的ES5代碼,第二個參數是轉換的配置對象。
Node腳本還有一種特殊的babel
用法,即把babel
加載爲require
命令的一個鉤子。安裝babel-core
和babel-preset-es2015
之後,先在項目的根目錄下面,設置一個配置文件.babelrc
。
// .babelrc{ "presets": ["es2015"]}
而後,在你的應用的入口腳本(entry script)頭部,加入下面的語句。
require("babel-core/register");
有了上面這行語句,後面全部經過require
命令加載的後綴名爲.es6
、.es
、.jsx
和.js
的腳本,都會先經過babel
轉碼後再加載。
須要注意的是,Babel默認不會轉換Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局對象,以及一些定義在全局對象上的方法(好比Object.assign
)。若是你用到了這些功能,當前的運行環境又不支持。就須要安裝babel-polyfill
模塊。
$ npm install babel-polyfill --save
而後,在全部腳本頭部加上一行。
require('babel-polyfill');// 或者import 'babel-polyfill';
Babel提供一個REPL在線編譯器,能夠在線將ES6代碼轉爲ES5代碼。轉換後的代碼,能夠直接做爲ES5代碼插入網頁運行
Google公司的Traceur轉碼器,也能夠將ES6代碼轉爲ES5代碼。
Traceur容許將ES6代碼直接插入網頁。首先,必須在網頁頭部加載Traceur庫文件。
<!-- 加載Traceur編譯器 --><script src="http://google.github.io/traceur-compiler/bin/traceur.js" type="text/javascript"></script><!-- 將Traceur編譯器用於網頁 --><script src="http://google.github.io/traceur-compiler/src/bootstrap.js" type="text/javascript"></script><!-- 打開實驗選項,不然有些特性可能編譯不成功 --><script> traceur.options.experimental = true;</script>
接下來,就能夠把ES6代碼放入上面這些代碼的下方。
<script type="module"> class Calc { constructor(){ console.log('Calc constructor'); } add(a, b){ return a + b; } } var c = new Calc(); console.log(c.add(4,5));</script>
正常狀況下,上面代碼會在控制檯打印出9。
注意,script
標籤的type
屬性的值是module
,而不是text/javascript
。這是Traceur編譯器識別ES6代碼的標識,編譯器會自動將全部type=module
的代碼編譯爲ES5,而後再交給瀏覽器執行。
若是ES6代碼是一個外部文件,也能夠用script
標籤插入網頁。
<script type="module" src="calc.js" ></script>
Traceur也提供一個在線編譯器,能夠在線將ES6代碼轉爲ES5代碼。轉換後的代碼,能夠直接做爲ES5代碼插入網頁運行。
上面的例子轉爲ES5代碼運行,就是下面這個樣子。
<script src="http://google.github.io/traceur-compiler/bin/traceur.js" type="text/javascript"></script><script src="http://google.github.io/traceur-compiler/src/bootstrap.js" type="text/javascript"></script><script> traceur.options.experimental = true;</script><script>$traceurRuntime.ModuleStore.getAnonymousModule(function() { "use strict"; var Calc = function Calc() { console.log('Calc constructor'); }; ($traceurRuntime.createClass)(Calc, {add: function(a, b) { return a + b; }}, {}); var c = new Calc(); console.log(c.add(4, 5)); return {};});</script>
做爲命令行工具使用時,Traceur是一個Node.js的模塊,首先須要用npm安裝。
$ npm install -g traceur
安裝成功後,就能夠在命令行下使用traceur了。
traceur直接運行es6腳本文件,會在標準輸出顯示運行結果,之前面的calc.js
爲例。
$ traceur calc.js Calc constructor9
若是要將ES6腳本轉爲ES5保存,要採用下面的寫法
$ traceur --script calc.es6.js --out calc.es5.js
上面代碼的--script
選項表示指定輸入文件,--out
選項表示指定輸出文件。
爲了防止有些特性編譯不成功,最好加上--experimental
選項。
$ traceur --script calc.es6.js --out calc.es5.js --experimental
命令行下轉換的文件,就能夠放到瀏覽器中運行。
Traceur的Node.js用法以下(假定已安裝traceur模塊)。
var traceur = require('traceur');var fs = require('fs');// 將ES6腳本轉爲字符串var contents = fs.readFileSync('es6-file.js').toString();var result = traceur.compile(contents, { filename: 'es6-file.js', sourceMap: true, // 其餘設置 modules: 'commonjs'});if (result.error) throw result.error;// result對象的js屬性就是轉換後的ES5代碼fs.writeFileSync('out.js', result.js);// sourceMap屬性對應map文件fs.writeFileSync('out.js.map', result.sourceMap);
2013年3月,ES6的草案封閉,再也不接受新功能了。新的功能將被加入ES7。
任何人均可以向TC39提案,從提案到變成正式標準,須要經歷五個階段。每一個階段的變更都須要由TC39委員會批准。
Stage 0 - Strawman(展現階段)
Stage 1 - Proposal(徵求意見階段)
Stage 2 - Draft(草案階段)
Stage 3 - Candidate(候選人階段)
Stage 4 - Finished(定案階段)
一個提案只要能進入Stage 2,就差很少等於確定會包括在ES7裏面。
本書的寫做目標之一,是跟蹤ECMAScript語言的最新進展。對於那些明確的、或者頗有但願列入ES7的功能,尤爲是那些Babel已經支持的功能,都將予以介紹。
本書介紹的ES7功能清單以下。
Stage 0:
es7.comprehensions:數組推導
es7.classProperties:類的屬性
es7.functionBind:函數的綁定運算符
Stage 1:
es7.decorators:修飾器
es7.exportExtensions:export的擴展寫法
es7.trailingFunctionCommas:函數參數的尾逗號
Stage 2:
es7.exponentiationOperator:指數運算符
es7.asyncFunctions:async函數
es7.objectRestSpread:對象的Rest參數和擴展運算符
ECMAScript當前的全部提案,能夠在TC39的官方網站Github.com/tc39/ecma262查看。
Babel轉碼器能夠經過安裝和使用插件來使用各個stage的語法。