天天看點

ECMAScript 6 入門簡介

ecmascript 6.0(以下簡稱es6)是javascript語言的下一代标準,已經在2015年6月正式釋出了。它的目标,是使得javascript語言可以用來編寫複雜的大型應用程式,成為企業級開發語言。

标準的制定者有計劃,以後每年釋出一次标準,使用年份作為版本。因為es6的第一個版本是在2015年釋出的,是以又稱ecmascript 2015(簡稱es2015)。

2016年6月,小幅修訂的《ecmascript 2016 标準》(簡稱 es2016)如期釋出。由于變動非常小(隻新增了數組執行個體的<code>includes</code>方法和指數運算符),是以

es2016 與 es2015 基本上是同一個标準,都被看作是 es6。根據計劃,2017年6月将釋出 es2017。

一個常見的問題是,ecmascript和javascript到底是什麼關系?

要講清楚這個問題,需要回顧曆史。1996年11月,javascript的創造者netscape公司,決定将javascript送出給國際标準化組織ecma,希望這種語言能夠成為國際标準。次年,ecma釋出262号标準檔案(ecma-262)的第一版,規定了浏覽器腳本語言的标準,并将這種語言稱為ecmascript,這個版本就是1.0版。

該标準從一開始就是針對javascript語言制定的,但是之是以不叫javascript,有兩個原因。一是商标,java是sun公司的商标,根據授權協定,隻有netscape公司可以合法地使用javascript這個名字,且javascript本身也已經被netscape公司注冊為商标。二是想展現這門語言的制定者是ecma,不是netscape,這樣有利于保證這門語言的開放性和中立性。

是以,ecmascript和javascript的關系是,前者是後者的規格,後者是前者的一種實作(另外的ecmascript方言還有jscript和actionscript)。日常場合,這兩個詞是可以互換的。

es6從開始制定到最後釋出,整整用了15年。

前面提到,ecmascript 1.0是1997年釋出的,接下來的兩年,連續釋出了ecmascript 2.0(1998年6月)和ecmascript 3.0(1999年12月)。3.0版是一個巨大的成功,在業界得到廣泛支援,成為通行标準,奠定了javascript語言的基本文法,以後的版本完全繼承。直到今天,初學者一開始學習javascript,其實就是在學3.0版的文法。

2000年,ecmascript 4.0開始醞釀。這個版本最後沒有通過,但是它的大部分内容被es6繼承了。是以,es6制定的起點其實是2000年。

為什麼es4沒有通過呢?因為這個版本太激進了,對es3做了徹底更新,導緻标準委員會的一些成員不願意接受。ecma的第39号技術專家委員會(technical committee 39,簡稱tc39)負責制訂ecmascript标準,成員包括microsoft、mozilla、google等大公司。

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年。

安裝nvm需要打開指令行視窗,運作下面的指令。

上面指令的<code>version number</code>處,需要用版本号替換。本節寫作時的版本号是<code>v0.29.0</code>。該指令運作後,<code>nvm</code>會預設安裝在使用者主目錄的<code>.nvm</code>子目錄。

然後,激活<code>nvm</code>。

激活以後,安裝node的最新版。

安裝完成後,切換到該版本。

使用下面的指令,可以檢視node所有已經實作的es6特性。

上面指令的輸出結果,會因為版本的不同而有所不同。

上面的原始代碼用了箭頭函數,這個特性還沒有得到廣泛支援,babel将其轉為普通函數,就能在現有的javascript環境執行了。

babel的配置檔案是<code>.babelrc</code>,存放在項目的根目錄下。使用babel的第一步,就是配置這個檔案。

該檔案用來設定轉碼規則和插件,基本格式如下。

<code>presets</code>字段設定轉碼規則,官方提供以下的規則集,你可以根據需要安裝。

然後,将這些規則加入<code>.babelrc</code>。

注意,以下所有babel工具和子產品的使用,都必須先寫好<code>.babelrc</code>。

babel提供<code>babel-cli</code>工具,用于指令行轉碼。

它的安裝指令如下。

基本用法如下。

上面代碼是在全局環境下,進行babel轉碼。這意味着,如果項目要運作,全局環境必須有babel,也就是說項目産生了對環境的依賴。另一方面,這樣做也無法支援不同項目使用不同版本的babel。

一個解決辦法是将<code>babel-cli</code>安裝在項目之中。

然後,改寫<code>package.json</code>。

轉碼的時候,就執行下面的指令。

<code>babel-cli</code>工具自帶一個<code>babel-node</code>指令,提供一個支援es6的repl環境。它支援node的repl環境的所有功能,而且可以直接運作es6代碼。

它不用單獨安裝,而是随<code>babel-cli</code>一起安裝。然後,執行<code>babel-node</code>就進入repl環境。

<code>babel-node</code>指令可以直接運作es6腳本。将上面的代碼放入腳本檔案<code>es6.js</code>,然後直接運作。

<code>babel-node</code>也可以安裝在項目中。

上面代碼中,使用<code>babel-node</code>替代<code>node</code>,這樣<code>script.js</code>本身就不用做任何轉碼處理。

<code>babel-register</code>子產品改寫<code>require</code>指令,為它加上一個鈎子。此後,每當使用<code>require</code>加載<code>.js</code>、<code>.jsx</code>、<code>.es</code>和<code>.es6</code>字尾名的檔案,就會先用babel進行轉碼。

使用時,必須首先加載<code>babel-register</code>。

然後,就不需要手動對<code>index.js</code>轉碼了。

需要注意的是,<code>babel-register</code>隻會對<code>require</code>指令加載的檔案轉碼,而不會對目前檔案轉碼。另外,由于它是實時轉碼,是以隻适合在開發環境使用。

如果某些代碼需要調用babel的api進行轉碼,就要使用<code>babel-core</code>子產品。

安裝指令如下。

然後,在項目中就可以調用<code>babel-core</code>。

下面是一個例子。

上面代碼中,<code>transform</code>方法的第一個參數是一個字元串,表示需要被轉換的es6代碼,第二個參數是轉換的配置對象。

babel預設隻轉換新的javascript句法(syntax),而不轉換新的api,比如iterator、generator、set、maps、proxy、reflect、symbol、promise等全局對象,以及一些定義在全局對象上的方法(比如<code>object.assign</code>)都不會轉碼。

舉例來說,es6在<code>array</code>對象上新增了<code>array.from</code>方法。babel就不會轉碼這個方法。如果想讓這個方法運作,必須使用<code>babel-polyfill</code>,為目前環境提供一個墊片。

然後,在腳本頭部,加入如下一行代碼。

babel也可以用于浏覽器環境。但是,從babel 6.0開始,不再直接提供浏覽器版本,而是要用建構工具建構出來。如果你沒有或不想使用建構工具,可以通過安裝5.x版本的<code>babel-core</code>子產品擷取。

運作上面的指令以後,就可以在目前目錄的<code>node_modules/babel-core/</code>子目錄裡面,找到<code>babel</code>的浏覽器版本<code>browser.js</code>(未精簡)和<code>browser.min.js</code>(已精簡)。

然後,将下面的代碼插入網頁。

上面代碼中,<code>browser.js</code>是babel提供的轉換器腳本,可以在浏覽器運作。使用者的es6腳本放在<code>script</code>标簽之中,但是要注明<code>type="text/babel"</code>。

注意,網頁中實時将es6代碼轉為es5,對性能會有影響。生産環境需要加載已經轉碼完成的腳本。

下面是如何将代碼打包成浏覽器可以使用的腳本,以<code>babel</code>配合<code>browserify</code>為例。首先,安裝<code>babelify</code>子產品。

然後,再用指令行轉換es6腳本。

上面代碼将es6腳本<code>script.js</code>,轉為<code>bundle.js</code>,浏覽器直接加載後者就可以了。

在<code>package.json</code>設定下面的代碼,就不用每次指令行都輸入參數了。

許多工具需要babel進行前置轉碼,這裡舉兩個例子:eslint和mocha。

eslint用于靜态檢查代碼的文法和風格,安裝指令如下。

然後,在項目根目錄下,建立一個配置檔案<code>.eslintrc</code>,在其中加入<code>parser</code>字段。

再在<code>package.json</code>之中,加入相應的<code>scripts</code>腳本。

mocha則是一個測試架構,如果需要執行使用es6文法的測試腳本,可以修改<code>package.json</code>的<code>scripts.test</code>。

上面指令中,<code>--compilers</code>參數指定腳本的轉碼器,規定字尾名為<code>js</code>的檔案,都需要使用<code>babel-core/register</code>先轉碼。

traceur允許将es6代碼直接插入網頁。首先,必須在網頁頭部加載traceur庫檔案。

上面代碼中,一共有4個<code>script</code>标簽。第一個是加載traceur的庫檔案,第二個和第三個是将這個庫檔案用于浏覽器環境,第四個則是加載使用者腳本,這個腳本裡面可以使用es6代碼。

注意,第四個<code>script</code>标簽的<code>type</code>屬性的值是<code>module</code>,而不是<code>text/javascript</code>。這是traceur編譯器識别es6代碼的标志,編譯器會自動将所有<code>type=module</code>的代碼編譯為es5,然後再交給浏覽器執行。

除了引用外部es6腳本,也可以直接在網頁中放置es6代碼。

正常情況下,上面代碼會在控制台列印出9。

如果想對traceur的行為有精确控制,可以采用下面參數配置的寫法。

上面代碼中,首先生成traceur的全局對象<code>window.system</code>,然後<code>system.import</code>方法可以用來加載es6子產品。加載的時候,需要傳入一個配置對象<code>metadata</code>,該對象的<code>traceuroptions</code>屬性可以配置支援es6功能。如果設為<code>experimental: true</code>,就表示除了es6以外,還支援一些實驗性的新功能。

上面的例子轉為es5代碼運作,就是下面這個樣子。

作為指令行工具使用時,traceur是一個node的子產品,首先需要用npm安裝。

安裝成功後,就可以在指令行下使用traceur了。

traceur直接運作es6腳本檔案,會在标準輸出顯示運作結果,以前面的<code>calc.js</code>為例。

如果要将es6腳本轉為es5儲存,要采用下面的寫法。

上面代碼的<code>--script</code>選項表示指定輸入檔案,<code>--out</code>選項表示指定輸出檔案。

為了防止有些特性編譯不成功,最好加上<code>--experimental</code>選項。

指令行下轉換生成的檔案,就可以直接放到浏覽器中運作。

traceur的node.js用法如下(假定已安裝traceur子產品)。

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:

function bind syntax:函數的綁定運算符

string.prototype.at:字元串的靜态方法at

stage 1:

class and property decorators:class的修飾器

class property declarations:class的屬性聲明

additional export-from statements:export的寫法改進

string.prototype.{trimleft,trimright}:字元串删除頭尾空格的方法

stage 2:

rest/spread properties:對象的rest參數和擴充運算符

stage 3

simd api:“單指令,多資料”指令集

async functions:async函數

object.values/object.entries:object的靜态方法values()和entries()

string padding:字元串長度補全

trailing commas in function parameter lists and calls:函數參數的尾逗号

object.getownpropertydescriptors:object的靜态方法getownpropertydescriptors

stage 4:

array.prototype.includes:數組執行個體的includes方法

exponentiation operator:指數運算符

babel轉碼器可以通過安裝和使用插件來使用各個stage的文法。

繼續閱讀