ecmascript和babel的淵源

ecma

  • 中文名: 歐洲計算機制造聯合會
  • 外文名: European Computer Manufactures Association
  • 地 區: 日內瓦
  • 縮 寫: ECMA
  • 目 的: 信息處理和電信系統
  • 包 括: 程序語言和輸入輸出
  • 組 織: 國際標準化組織
這個組織的目標是評估,開發和認可電信和計算機標準。大家決定把ECMA的總部設在日內瓦是因爲這樣能夠讓它與其它與之協同工作的標準制定組織更接近一些,比方說國際標準化組織(ISO)和國際電子技術協會(IEC)。ECMA是“European Computer Manufactures Association”的縮寫,中文稱歐洲計算機制造聯合會。是1961年成立的旨在建立統一的電腦操作格式標準--包括程序語言和輸入輸出的組織。
主要任務是研究信息和通訊技術方面的標準併發布有關技術報告。ECMA並不是官方機構,而是由主流廠商組成的,他們經常與其他國際組織進行合作。就象ECMA的章程中所說的那樣,這個非盈利組織的目標是發展“標準和技術報告以便促進和標準化對信息處理和電信系統的使用過程。

目前已經可以確認的標準:注:此名單僅部分收錄

ECMA-6 7位被編碼的字符集(同一樣 ISO/IEC 646/ITU-T T.50)
ECMA-13文件結構和標記磁帶(最新ISO 1001)
ECMA-35 ISO/IEC 2022年 字符內碼
ECMA-43 8位被編碼的字符集(和一樣ISO/IEC 4873)
ECMA-48 ANSI逃命代碼 (和一樣ISO/IEC 6429)
ECMA-58 8英寸 軟盤
ECMA-59 8英寸 軟盤
ECMA-66 5¼-英寸 軟盤
ECMA-69 8英寸 軟盤
ECMA-70 5¼ -英寸 軟盤
ECMA-74信息技術和電信設備散發的空氣傳播的噪音的測量(和一樣ISO 7779)
ECMA-78 5¼ -英寸 軟盤
ECMA-94 8位編碼字符集(同一樣 ISO/IEC 8859-1, -2, -3和-4)
ECMA-99 5¼-英寸1.2兆字節 軟盤 (也ISO 8630)
ECMA-100 3½-英寸 軟盤 (也ISO 8660)
ECMA-107 文件分配表 (FAT)文件系統
ECMA-113 8位被編碼的字符集,拉丁語或斯拉夫(同一樣 ISO/IEC 8859-5)
ECMA-114 8位被編碼的字符集,拉丁語或阿拉伯語(同一樣 ISO/IEC 8859-6)
ECMA-118 8位被編碼的字符集,拉丁語或希臘語(同一樣 ISO/IEC 8859-7)
ECMA-119 CD-ROM 文件系統(以後被採取 ISO 9660:1988)
ECMA-121 8位被編碼的字符集,拉丁語或希伯來語(同一樣 ISO/IEC 8859-8)
ECMA-125 3½-英寸 軟盤 (也ISO 9529)
ECMA-128 8位被編碼的字符集(同一樣 ISO/IEC 8859-9)
ECMA-130 CD-ROM 黃皮書
ECMA-139 4mm 數字資料存貯 (二氨基二苯基碸)彈藥筒(和一樣ISO/IEC 10777)
ECMA-144 8位被編碼的字符集(同一樣 ISO/IEC 8859-10)
ECMA-146 4mm DAT 數據插件(和一樣ISO/IEC 11321)
ECMA-167 普遍盤格式
ECMA-168 ISO 9660 第3級(ISO/IEC 13490)
ECMA-182 週期性多餘信息檢驗 多項CRC-64-ECMA-182
ECMA-234應用程序編程接口爲 窗口3.1
ECMA-262 ECMAScript (規範化 腳本(script)語言)
ECMA-334 C#編程語言
ECMA-335 共同語言基礎設施
ECMA-340 NFC標準ISO18092(ECMA免費版)
ECMA-352 NFC標準ISO21481(ECMA免費版)
ECMA-357 ECMAScript爲XML (E4X)
ECMA-363 通用3D 文件格式
ECMA-365 通用媒體光盤(用於PSP)
ECMA-368 超寬物理和MAC層
ECMA-369 超寬MAC-PHY接口
ECMA-372 C++/CLI
ECMA-376 辦公文檔開放XML
ECMA-377 200GB的HVD插卡
ECMA-378 100GB的HVD-ROM光碟

而其中就有本文重點介紹的ECMAscript

ECMAscript/ES5/ES6/ES20XX

這裏主要簡單的介紹一下關於JavaScript的一些歷史。

ECMAscript

ECMAscript是基於Netscape javaScript的一種標準腳本語言。它也是一種基於對象的語言,通過DOM可以操作網頁上的任何對象。可以增加、刪除、移動或者改變對象。使得網頁的交互性大大提高。更多ECMAscript信息和歷史

ECMAScript是一種由Ecma國際(前身爲歐洲計算機製造商協會)通過ECMA-262標準化的腳本程序設計語言。這種語言在萬維網上應用廣泛,它往往被稱爲JavaScriptJScript,但實際上後兩者是ECMA-262標準的實現和擴展。

ECMA的第39號技術專家委員會(Technical Committee 39,簡稱TC39)負責制訂ECMAScript標準,成員包括Microsoft、Mozilla、Google等大公司。TC39的總體考慮是,ES5與ES3基本保持兼容,較大的語法修正和新功能加入,將由JavaScript.next完成。

瞭解更多TC39的進度可以關注tc39ecma262--githubtc39標準進度

ECMAscript/ES歷史

ESECMAScript 的縮寫。每次看到 ES 後面跟着數字,是 ECMAScript 的不同版本。實際上一共有 9 個版本【截止時間2018年,2018-11月的部分達到stage4的提案已經作爲ES2019的部分了】。我們來深入瞭解下:

  1. ES1:1997 年 6 月  ——  
  2. ES2:1998 年 6 月  ——  
  3. ES3:1999 年 12月  ——  
  4. ES4:未通過

這是前 4 個版本的 ECMAScript,這裏簡單過一下。僅僅讓你知道前 3 個版本每年出一個,而第 4 個版本因爲政治因素未通過。

  • ES5:2009 年 12月:將近 10 年之後,ES5 在 2009 年發佈。而下個版本的 ECMAScript 也花了 6 年才發佈,【目前ie8還有部分標準沒有實現】。
  • ES6/ES2015:2015 年 6 月:也許困惑就是從這裏開始的。你可以看到, ES6 和 ES2015 實際上是同一個東西。
    起先被推廣的名字是 ES6 。然而組委會要求 ECMAScript 必須做到每年做一次更新。由此,這個版本被更名爲 ES 2015,且每年都需要更新,並命名爲當前年的後綴。

    從 2009 年發佈的 ES5 到 2015 年發佈的 ES6 共經歷了 6 年,語言的變化非常大,引入了很多新的語法和特性。爲了避免劇烈的變動,從 ES7(2016) 開始,版本發佈會變得更加頻繁,每次的變動也更小。每年會發佈一個新版本,其中包含所有已經完成的特性。
  • ES2016(ES7):2016 年 6 月:ECMAScript 的第 7 個版本。
  • ES2017(ES8):2017 年 6 月:ECMAScript 的第 8 個版本。
  • ES2018(ES9):2018 年 6 月:ECMAScript 的第 9 個版本。

由此可以知道,往後應scma組委會要求,TC39每年都會提交一個版本,可能每年提交的版本修改並不會增加非常多,但還是需要時刻關注

stage【新增特性過程】

每一項新特性,要最終納入 ECMAScript 規範中,TC39 擬定了一個處理過程,稱爲 TC39 process。其中共包含 5 個階段,Stage 0 ~ Stage 4stage的每個特性所處階段記錄--stage英文文檔介紹

TC39 遵循的原則是:分階段加入不同的語言特性。一旦提案成熟,TC39 會根據提案中的變動來更新規範。直到最近,TC39 依然依賴基於 Microsoft Word 的比較傳統的工作流程。但 ES3 出來之後,爲了使其達到規範,總共花了十年時間,幾乎沒有任何改變。之後,ES6 又花了四年才能實現。

ES6 出來之後,他們精簡了提案的修訂過程,以滿足現代化開發的需求。新流程使用 HTML 的超集來格式化提案。他們使用 GitHub pull requests,這有助於增加社區的參與,並且提出的提案數量也增加了。這個規範現在是一個 living standard,這意味着提案會更快,而且我們也不用等待新版本的規範出來。

新流程涉及五個不同的 Stage。一個提案越成熟,越有可能最終將其納入規範。

  1. Stage 0: strawman
    任何尚未提交作爲正式提案的討論、想法變更或者補充都被認爲是第 0 階段的“稻草人(strawman)”提案。

    任何 TC39 成員,或者註冊爲 TC39 貢獻者的會員,都可以提交 Stage 0 的提案。
  2. Stage 1: proposal
    該階段產生一個正式的提案。確定一個帶頭人來負責該提案,帶頭人(或者聯合帶頭人)必須是 TC39 的成員。描述清楚要解決的問題,

    解決方案中必須包含例子,API(high level AP) 以及關於相關的語義和算法。潛在問題也應該指出來,例如與其他特性的關係,實現它所面臨的挑戰。polyfill 和 demo 也是必要的。
  3. Stage 2: draft
    Stage 2 的提案應提供規範初稿。此時,語言的實現者開始觀察 runtime 的具體實現是否合理。該實現可以使用 polyfill 的方式,以便使代碼可在 runtime 中的行爲負責規範的定義。javascript 引擎的實現爲提案提供了原生支持。或者可以 Babel 這樣的編譯時編譯器來支持。本草案與最終標準中包含的特性不會有太大差別。草案之後,原則上只接受增量修改。

    草案中包含新增特性語法和語義的,儘可能的完善的形式說明,允許包含一些待辦事項或者佔位符。必須包含 2 個實驗性的具體實現,其中一個可以是用轉譯器實現的,例如 Babel。
  4. Stage 3: candidate
    Stage 3 提案是建議的候選提案。在這個高級階段,規範的編輯人員和評審人員必須在最終規範上簽字。Stage 3 的提案不會有太大的改變,在對外發布之前只是修正一些問題。規範文檔必須是完整的,評審人和 ECMAScript 的編輯要在規範上簽字。至少要有 2 個符合規範的具體實現。
  5. Stage 4: finished
    最後,當規範的實現至少通過兩個驗收測試時,提案進入 Stage 4。進入 Stage 4 的提案將包含在 ECMAScript 的下一個修訂版中。

    通過 Test 262 的驗收測試。有 2 個通過測試的實現,以獲取使用過程中的重要實踐經驗。ECMAScript 的編輯必須規範上的簽字。規格修訂和調度

TC39 打算每年七月向 ECMA 大會提交一份規範批准。以下是生成新規格修訂的大致時間表:

  • 2月1日:候選草案被生成。
  • 2月-3月:60 天時間進行投票決定草案的去留。
  • 3月 TC39 會議:第 4 階段的提案被納入,最終的語義被批准,從 master 新建一個 spec 的分支版本。只有編輯性的改變才能被接受。
  • 4月-6月:ECMA CC 和 ECMA GA 審查期。
  • 7月:由 ECMA 大會批准新標準

可以知道,每一年度的版本其實在當年的7-8月份已經基本確定,然後開始下一年的進度。

也正是由於歷史原因,有4點需要注意【以下截止時間2018-12,內容會被不斷地調整】:

  1. ES5的修改經歷了10年,而其中很多都是我們前端經常用到的內容,ES5的修改內容可以參考:Standard ECMA-262, 5.1 Edition / June 2011,由於標準都是向前兼容的,所以這個版本包含了es3之前的標準,es5增加的標準列表;
  2. ES6也是經歷了6年時間,在2015年發佈的,其中又發生了很多的變化,查看ES6的標準:es6標準,通用也是包含了es5和之前的標準,es6增加的標準列表1--es6增加的標準列表1
  3. 爲了避免這種較大的改動,TC39將會在每年提交一個版本,這樣的變化在2016年開始,而從2016~2018年中的已經完成到stage4的提案列表:es2016+的已定標準變化
  4. 而每一年的天的各個階段會有變化,查看當前年份的有效天內容:當前年份的活躍天stage3~1

標準的發佈,各大廠商是需要時間去做實現的,所以如果開發人員想第一時間來體驗新的提案帶來的便捷,肯定是需要把提案中的內容通過類似polyfill的方式來使用,這就是本文另一個重點babel的作用。

babel的出現

Babel 是一個通用的多用途 JavaScript 編譯器。通過 Babel 你可以使用(並創建)下一代的 JavaScript,以及下一代的 JavaScript 工具。

babel簡介

作爲一種語言,JavaScript 在不斷髮展,新的標準/提案和新的特性層出不窮。 在得到廣泛普及之前,Babel 能夠讓你提前(甚至數年)使用它們。

Babel 把用最新標準編寫的 JavaScript 代碼向下編譯成可以在今天隨處可用的版本。 這一過程叫做“源碼到源碼”編譯, 也被稱爲轉換編譯(transpiling,是一個自造合成詞,即轉換+編譯。以下也簡稱爲轉譯)。

例如,Babel 能夠將新的 ES2015 箭頭函數語法:

const square = n => n * n;
// 轉譯爲:
const square = function square(n) {
  return n * n;
};

不過 Babel 的用途並不止於此,它支持語法擴展,能支持像 React 所用的 JSX 語法,同時還支持用於靜態類型檢查的流式語法(Flow Syntax)

更重要的是,Babel 的一切都是簡單的插件,誰都可以創建自己的插件,利用 Babel 的全部威力去做任何事情。

再進一步,Babel 自身被分解成了數個核心模塊,任何人都可以利用它們來創建下一代的 JavaScript 工具。

babel7使用

由於 JavaScript 社區沒有統一的構建工具、框架、平臺等等,因此 Babel 正式集成了對所有主流工具的支持。 從 Gulp 到 Browserify,從 Ember 到 Meteor,不管你的環境設置如何,Babel 都有正式的集成支持。

鑑於babel的靈活性,除了配置主流工具webpackgulp等使用,也可以獨自使用;

  1. CLI: 使用命令來進行編譯
  2. Require hook: 在需要編譯的文件中引入require("babel-register");/import "babel-register";來編譯當前文件。

不過二者都需要配合配置文件.babelrc使用;下面主要示範CLI的使用。

Babel/CLI

BABELCLI 是一種在命令行下使用 Babel 編譯文件的簡單方法。

讓我們先全局安裝它來學習基礎知識。

$ npm install -D babel-cli

我們可以這樣來編譯我們的第一個文件:

$ ./node_modules/.bin/babel my-file.js

這將把編譯後的結果直接輸出至終端。使用 --out-file 或着 -o 可以將結果寫入到指定的文件。.

$ ./node_modules/.bin/babel example.js --out-file compiled.js
# 或
$ ./node_modules/.bin/babel example.js -o compiled.js

如果我們想要把一個目錄整個編譯成一個新的目錄,可以使用 --out-dir 或者 -d。.

$ ./node_modules/.bin/babel src --out-dir lib
# 或
$ ./node_modules/.bin/babel src -d lib

一般而言,編譯會被放在package.jsonscripts字段當中,

"scripts": {
    "test": "./node_modules/mocha/bin/mocha",
    "build": "./node_modules/.bin/babel src -d lib",
    "prepublish": "npm run build"
  },

配置文件.babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "browsers": [
            "last 2 versions",
            "safari >= 7"
          ],
          "chrome": 52,
          "node": "6.10.0"
        },
        "modules": "commonjs",
        "useBuiltIns": "usage"
      }
    ]
  ],
  "plugins": [
    "@babel/plugin-syntax-dynamic-import",
    "@babel/plugin-syntax-import-meta",
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-proposal-nullish-coalescing-operator",
    "@babel/plugin-proposal-do-expressions"
  ]
}

plugins

pluginsbabel實現es2015+的新的語法,而每實現一種語法的編譯,都是一個plugins

實例:@babel/plugin-transform-arrow-functions可以實現下面這個編譯過程。

const square = n => n * n;
// 轉譯爲:
const square = function square(n) {
  return n * n;
};

目前的plugins的集合目前可以查看:babel的plugins集合

@babel/preset-env

Sidenote, if no targets are specified, @babel/preset-env behaves exactly the same as @babel/preset-es2015, @babel/preset-es2016 and @babel/preset-es2017 together (or the deprecated babel-preset-latest).

可以知道,@babel/preset-env是完成了stage4以內的所有語法,同時添加了更多的配置項;

"presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "browsers": [
            "last 2 versions",
            "safari >= 7"
          ],
          "chrome": 52,
          "node": "6.10.0"
        },
        "modules": "commonjs",
        "useBuiltIns": "usage"
      }
    ]
  ],

更多的詳細信息查看:babel的預設使用

比較重要的是三個地方:

  1. targets字段:適配所包含的運行環境,根據環境進行打包。
  2. modules打包後的模塊:
  3. useBuiltInspolyfill的引入方式,
    "usage" | "entry" | false, defaults to false.

polyfill

Babel 是處於構建時(也就是傳統Java等語言的編譯時),轉譯出來的結果在默認情況下並不包括 ES6 對運行時的擴展,例如,builtins(內建,包括 Promise、Set、Map 等)、內建類型上的原型擴展(如 ES6 對 Array、Object、String 等內建類型原型上的擴展)以及Regenerator(用於generators / yield)等都不包括在內。

需要配合useBuiltIns字段來使用。

  1. "useBuiltIns": false
    不在代碼中使用polyfills,表現形式和@babel/preset-latest一樣,當使用ES6+語法及API時,在不支持的環境下會報錯。
  2. "useBuiltIns":"entry"
    在項目入口引入一次(多次引入會報錯)

    import "@babel/polyfill"
    // or
    require("@babel/polyfill")

    插件@babel/preset-env會將把@babel/polyfill根據實際需求打散,只留下必須的,例如:

    // input file
    import "@babel/polyfill";
    // Out (different based on environment)
    import "core-js/modules/es6.promise";
    import "core-js/modules/es7.string.pad-start";
    import "core-js/modules/es7.string.pad-end";
    import "core-js/modules/es7.array.includes";
  3. "useBuiltIns":"usage"
    在文件需要的位置單獨按需引入,可以保證在每個bundler中只引入一份。例如:

    // In
    //a.js
    var a = new Promise();
    
    //b.js
    var b = new Map();
    // Out (if environment doesn't support it)
    import "core-js/modules/es6.promise";
    var a = new Promise();
    
    import "core-js/modules/es6.map";
    var b = new Map();
    
    // Out (if environment supports it)
    var a = new Promise();
    var b = new Map();

babel7之前的一些歷史

bale7發佈;可以說是對以前改變了不少,最爲主要的是以下兩點:

babel-preset-es20xx

babel-preset-es2015babel-preset-es2016babel-preset-es2017babel配合ECMA組委會給TC39的要求,希望ECMA-262能夠每年都更新一個版本,所以每年發了一個版本的話,那麼babel就會把新的語法創建一個新的預設,以年份命名。

這樣看似很好的,不過有一個問題,隨着每年的推進,開發者需要每一年就在配置文件中添加一個當年的預設,所以把這些作爲stage4以內的完成的ECMA-261提案集合到一個預設@babel/preset-env;而babel只要不停地更新這個預設就可以了。

stage的移除

之前提到了,關於TC39的提案進程,有的時候除了stage4的提案外,開發者還想使用其他的進度上的提案,babel使用了babel-preset-stage-0babel-preset-stage-1babel-preset-stage-2babel-preset-stage-3這四個預設分別對應四個階段,

做法看似很好,同樣有一個隱患,很多時候,開發者只想使用某一個階段的提案,而不是把這個階段的所有提案都引進來,所以babel7的做法是把這個stage-x的預設全都廢棄,而是讓開發者來進行自己手動將需要的對應階段的插件引入即可,而不用採用預設的方案,因爲預設就是插件的集合。

參考:
es簡介譯文
es個版本的增加項
es2015的
es6增加
es5增加
es和ecmascript關係
babel預設
babel翻譯文檔
babel使用實例
tc39的進程理解
plugins必知插件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章