成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

深入理解 Babel - 微內(nèi)核架構(gòu)與 ECMAScript 標(biāo)準(zhǔn)化

開發(fā) 前端
本文介紹了 Babel 的概述/微內(nèi)核架構(gòu)/ECMAScript標(biāo)準(zhǔn)化方面的設(shè)計(jì)思想和部分實(shí)現(xiàn)原理。

隨著瀏覽器版本的持續(xù)更新,瀏覽器對JavaScript的支持越來越強(qiáng)大,Babel的重要性顯得較低了。但Babel的設(shè)計(jì)思路、背后依賴的ECMAScript標(biāo)準(zhǔn)化思想仍然值得借鑒。

本文涉及的Babel版本主要是V7.16及以下,截至發(fā)文時(shí),Babel最新發(fā)布的版本是V7.25.6,未出現(xiàn)大版本更新,近2年也進(jìn)入了穩(wěn)定迭代期,本文的分析思路基本適用目前的Babel設(shè)計(jì)。

一、Babel簡介

Babel是什么

Babel是JavaScript轉(zhuǎn)譯器,通過Babel,開發(fā)者可以自由使用下一代ECMAScript 語法。高版本ECMAScript語法將被轉(zhuǎn)譯為低版本語法,以便順利運(yùn)行在各類環(huán)境,如低版本瀏覽器、低版本 Node.js 等。

Babel 是轉(zhuǎn)譯器,不是編譯器。下面是轉(zhuǎn)譯和編譯的區(qū)別:

編譯,一般指將一種語言轉(zhuǎn)換為另一種語法和抽象程度等都不同的語言,常見的比如 gcc 編譯器。

轉(zhuǎn)譯,一般指將一種語言轉(zhuǎn)換為不同版本或者抽象程度相同的語言,比如 Babel 可以把 ECMAScript 6 語法轉(zhuǎn)譯為 ECMAScript 5語法。

利用 Babel,開發(fā)者可以使用 ECMAScript 的各種新特性進(jìn)行開發(fā),同時(shí)花極少的精力關(guān)注瀏覽器或其他JS運(yùn)行環(huán)境對新特性的支持。甚至,開發(fā)者可以根據(jù)自身需要,創(chuàng)造屬于自己的 JavaScript 語法。

Babel在轉(zhuǎn)譯的時(shí)候,會對源碼進(jìn)行以下處理: 語法轉(zhuǎn)譯(Syntax)和添加API Polyfill。

圖片圖片

  • 語法(Syntax)部分Babel 支持識別高版本語法,并通過插件將源碼從高版本語法轉(zhuǎn)譯為低版本語法,如:

箭頭函數(shù) () => {} 轉(zhuǎn)為普通函數(shù) function() {}。

const / let 轉(zhuǎn)譯為var

  • API Polyfill有些運(yùn)行時(shí)相關(guān)的 API,語法轉(zhuǎn)譯無法解決它們對低版本瀏覽器等環(huán)境的兼容性問題,因此 Babel 通過與 core-js 等工具的配合,實(shí)現(xiàn) API 部分對目標(biāo)環(huán)境(通常是低版本瀏覽器等)的兼容。例如[1, 2, 3].include、Promise等 API,Babel 在處理時(shí),如果目標(biāo)環(huán)節(jié)可能不支持原生的 include / Promise 的話,Babel 會在轉(zhuǎn)譯結(jié)果中嵌入 include / Promise 的自定義實(shí)現(xiàn)。有多種方式可以使用 Babel,如: 命令行(babel-cli、babel-node)、瀏覽器(babel-standalone)、API 調(diào)用(babel-core)、webpack loader(babel-loader)等。

轉(zhuǎn)譯過程

和多數(shù)轉(zhuǎn)譯器相同,Babel 運(yùn)行的生命周期主要是 3 個(gè)階段: 解析、轉(zhuǎn)換、代碼生成。

這個(gè)過程涉及抽象語法樹:

抽象語法樹(Abstract Syntax Tree,AST),或簡稱語法樹(Syntax tree),是源代碼語法結(jié)構(gòu)的一種抽象表示。

AST 是樹形對象,以結(jié)構(gòu)化的形式表示編程語言的語法結(jié)構(gòu),樹上的每個(gè)節(jié)點(diǎn)都表示源代碼中的一種結(jié)構(gòu)。

圖片圖片

源碼字符串需要經(jīng)轉(zhuǎn)譯器生成 AST,轉(zhuǎn)譯器有很多種,不同轉(zhuǎn)譯器,生成的AST對象格式細(xì)節(jié)可能有差異,但共同點(diǎn)為: 都是樹形對象、該樹形對象描述了節(jié)點(diǎn)特征、各節(jié)點(diǎn)之間的關(guān)系(兄弟、父子等)。

以下是 Babel 生命周期的三個(gè)過程:

  • 解析(Parsing): Code1 ==> 抽象語法樹1解析過程包括 2 個(gè)環(huán)節(jié): 詞法解析、語法解析,最終生成抽象語法樹。詞法解析階段,代碼字符串被解析為 token 令牌數(shù)組,數(shù)組項(xiàng)是一個(gè)對象,包括: 代碼字符碎片的值、位置、類型等信息。token 數(shù)組是平鋪式的數(shù)組,沒有嵌套的結(jié)構(gòu)信息,它是為語法解析階段做準(zhǔn)備的。語法解析階段,token 令牌數(shù)組被解析為結(jié)構(gòu)化的抽放語法樹對象(AST)。babel-parser 完成該階段的主要功能。

圖片圖片

  • 轉(zhuǎn)換(Transformation): AST1 ==> AST2Babel 生成 AST 后,會對 AST 進(jìn)行遍歷,遍歷過程中,各類插件對原 AST 對象進(jìn)行增刪改查等操作,AST 結(jié)構(gòu)被修改。

圖片圖片

  • 代碼生成(Generation): AST2 ==> Code2Babel 將修改后的 AST 對象轉(zhuǎn)目標(biāo)代碼字符串。babel-generator 完成該階段的主要功能。

圖片圖片

二、Babel微內(nèi)核架構(gòu)

微內(nèi)核架構(gòu)

Babel 采用微內(nèi)核架構(gòu),其內(nèi)核保留核心功能,其余功能利用外部工具和插件機(jī)制實(shí)現(xiàn),也體現(xiàn)了"開放-封閉"的設(shè)計(jì)原則。

圖片圖片

除了微內(nèi)核設(shè)計(jì)架構(gòu),Babel 的模塊設(shè)計(jì)也可以做如下分類:

圖片圖片

轉(zhuǎn)譯模塊

轉(zhuǎn)譯模塊位于 Babel 微內(nèi)核架構(gòu)的"微內(nèi)核"部分,該部分主要負(fù)責(zé)代碼轉(zhuǎn)譯,也就是上面提到的"解析-轉(zhuǎn)換-代碼生成"過程。

該模塊主要包括: babel-parser、babel-traverse、babel-generator。

  • babel-parser負(fù)責(zé)將代碼字符串轉(zhuǎn)為 AST 對象。有 2 點(diǎn)值得一提:

babel-parser 本身并不會對 AST 做轉(zhuǎn)換操作,只是負(fù)責(zé)解析出 AST。AST 轉(zhuǎn)換部分交由各類 plugins 和 presets 處理。

babel-parser 內(nèi)置了對 ESNext/TypeScript/JSX/Flow 最新版本語法的支持,但很多默認(rèn)是不開啟的,目前沒有開放插件機(jī)制擴(kuò)展新語法。

  • babel-traverse在轉(zhuǎn)譯過程中,babel-traverse 負(fù)責(zé)遍歷 AST 節(jié)點(diǎn),并根據(jù)配置的 plugins/presets,在遍歷過程中,對各個(gè) AST 節(jié)點(diǎn)進(jìn)行增刪改查的操作。AST 是一個(gè)樹形對象,遍歷 AST 對象的過程也是一個(gè)深度優(yōu)先遍歷的過程。

  • babel-generator負(fù)責(zé)將 AST 節(jié)點(diǎn),轉(zhuǎn)為代碼字符串,同時(shí)也可以生成 source-map。

插件模塊

插件模塊包括 plugins、presets。

  • plugins豐富的插件,幫助 Babel 成為一個(gè)非常成功的轉(zhuǎn)譯工具。對 AST 的遍歷、轉(zhuǎn)換是 Babel 轉(zhuǎn)譯的核心功能,但 Babel 本身并不參與該過程,將這些功能作為插件引入到運(yùn)行時(shí)。具體來說,babel-core 作為核心工具,不提供對 AST 的修改邏輯,通過調(diào)用各類插件,實(shí)現(xiàn)對 AST 的修改。Babel的插件分為語法插件和轉(zhuǎn)換插件。

語法插件

值得注意的是,babel-parser 負(fù)責(zé)將 JavaScript 代碼解析出抽象語法樹(AST),它支持全面識別 ESNext/TypeScript/JSX/Flow 等語法,目前由 Babel 團(tuán)隊(duì)開發(fā)維護(hù),不支持插件化。

Babel 插件生態(tài)中的語法插件,其功能就是作為"開關(guān)",配置是否開啟 babel-parser 的某些語法轉(zhuǎn)譯功能。

語法插件在 Babel 源碼中,以 babel-plugin-syntax 開頭。

舉個(gè)例子:

babel-plugin-syntax-decorators負(fù)責(zé)開啟 babel-parser 對裝飾器的語法支持。

babel-plugin-syntax-dynamic-import負(fù)責(zé)開啟 babel-parser 對 import 語句的語法支持。

babel-plugin-syntax-jsx負(fù)責(zé)開啟 babel-parser 對 jsx 語法的支持。

  • 轉(zhuǎn)換插件轉(zhuǎn)換插件就是社區(qū)里常說的 Babel 插件,負(fù)責(zé)轉(zhuǎn)換 AST 節(jié)點(diǎn)。在介紹babel-traverse時(shí)提到,它負(fù)責(zé)遍歷AST對象,每個(gè)AST節(jié)點(diǎn)會被訪問到,等待轉(zhuǎn)換,轉(zhuǎn)換的部分,由"轉(zhuǎn)換插件"負(fù)責(zé)。轉(zhuǎn)換插件會提供一個(gè)叫做"Visitor"的對象,該對象的 Key 為節(jié)點(diǎn)名稱,Value 部分提供進(jìn)入該節(jié)點(diǎn)時(shí)、離開該節(jié)點(diǎn)時(shí)的回調(diào)函數(shù),在回調(diào)函數(shù)里,可以對該節(jié)點(diǎn)進(jìn)行一系列操作。"Visitor" 又稱為 "訪問者"。
// plugin 提供 visitor,在 visitor 中對 AST 節(jié)點(diǎn)操作
const visitor = {
    Program: {
        enter() {},
        exit() {},
    },


    CallExpression: {
        enter() {},
        exit() {},
    },


    NumberLiteral: {
        enter() {},
        exit() {},
    }
};
traverse(ast, visitor);

轉(zhuǎn)換插件在Babel源碼中,以 babel-plugin-transform 開頭。

舉個(gè)例子:

babel-plugin-transform-strict-mode

該插件攔截 Program 節(jié)點(diǎn),也就是整個(gè)程序的根節(jié)點(diǎn),添加 "use strict"指令。

visitor 節(jié)點(diǎn)值為函數(shù)時(shí),是 enter 回調(diào)的快捷方式。

{
    name: "transform-strict-mode",


    visitor: {
      Program(path) {
        const { node } = path;


        for (const directive of node.directives) {
          if (directive.value.value === "use strict") return;
        }


        path.unshiftContainer(
          "directives",
          t.directive(t.directiveLiteral("use strict")),
        );
      },
    },
  };
}
  • babel-plugin-transform-object-assign

該插件負(fù)責(zé)攔截函數(shù)調(diào)用表達(dá)式節(jié)點(diǎn) CallExpression,將 Object.assign 轉(zhuǎn)為 extends 寫法。

{
    name: "transform-object-assign",


    visitor: {
      CallExpression(path, file) {
        if (path.get("callee").matchesPattern("Object.assign")) {
          path.node.callee = file.addHelper("extends");
        }
      },
    },
}
  • PresetsBabel 插件的功能是細(xì)粒度的,大部分插件承擔(dān)了單一功能。而在實(shí)際開發(fā)過程中,往往需要支持對各類語法的支持。此時(shí),有兩種做法:

需要支持哪些特性,就分別引入支持該特性的插件

直接引入一個(gè)插件集合,涵蓋所需的各類插件功能

很顯然,第一種做法是相對麻煩的。針對第二種做法,Babel提供了插件集 preset。

preset 在 Babel 源碼中,以 babel-preset 開頭。

例如,Babel 已經(jīng)提供了幾種常用的 preset 供開發(fā)者使用:

babel-preset-env

babel-preset-react

babel-preset-flow

babel-preset-typescript

  • 插件運(yùn)行順序Babel 配置項(xiàng)中,plugins 和 presets 均以數(shù)組的形式配置,執(zhí)行時(shí)有先后順序。

plugins 在 presets之前運(yùn)行

plugins 按照數(shù)組正序執(zhí)行

presets 按照數(shù)組倒序執(zhí)行

圖片圖片

工具模塊

工具模塊提供 Babel 相關(guān)模塊所需的各類工具,以下一一簡要介紹:

  • babel-corebabel-core 對外提供了 Babel 多項(xiàng)功能的 API,如轉(zhuǎn)譯文件、轉(zhuǎn)譯代碼、創(chuàng)建/獲取配置等,在 Babel 官方文檔介紹的比較詳細(xì),不再贅述。值得注意的是,轉(zhuǎn)譯類的 API 均提供了同步和異步版本,如 transformSync/transfomAsync、parseSync/parseAsync。

  • babel-cliBabel 的命令行工具,可以直接轉(zhuǎn)譯文件夾/文件,它也提供了很多配置項(xiàng)做其他工作,官方文檔介紹的比較詳細(xì),感興趣的同學(xué)可以去 Babel 官網(wǎng)查看詳細(xì)配置。

  • babel-standaloneBabel 對外服務(wù)的很多包是基于 node 環(huán)境下使用的,babel-standalone 提供了瀏覽器下轉(zhuǎn)譯的方案。babel-standalone 內(nèi)置了所有 Babel 插件,所以體積還是比較大的,而且在瀏覽器端轉(zhuǎn)譯需要時(shí)間,比較適合開發(fā)、學(xué)習(xí)使用,不適合在生產(chǎn)環(huán)境使用。舉個(gè)例子:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>test babel-standalone</title>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="text/babel">
      const arr = [1, 2, 3];
      console.log(...arr);
</script>
  </head>
  <body></body>
</html>

在瀏覽器運(yùn)行該 html,可以看到,頁面結(jié)構(gòu)變成了:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>test babel-standalone</title>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="text/babel">
      const arr = [1, 2, 3];
      console.log(...arr);
</script>
    <script>
      "use strict";
      var _console;
      var arr = [1, 2, 3];
      (_console = console).log.apply(_console, arr); //# sourceMappingURL=data:application/json;charset=utf-8;base64...
</script>
  </head>
  <body></body>
</html>
  • babel-node

提供在命令行執(zhí)行高級語法的環(huán)境。

例如:

// index.js 里可以使用高級語法     
babel-node -e index.js

index.js 文件以及被其引入的其他文件均可以使用高級語法了。和 babel-cli 不同的是,babel-cli 只負(fù)責(zé)轉(zhuǎn)換,不在 node 運(yùn)行時(shí)執(zhí)行;babel-node 會在 node 運(yùn)行時(shí)執(zhí)行轉(zhuǎn)換,不適合生產(chǎn)環(huán)境使用。

  • babel-register

在源文件中,引入babel-register,如 index.js:

index.js

require('babel-register');     
require('./run');

run.js

import fs from 'fs';     
console.log(fs);

執(zhí)行 node index 時(shí),run.js 就不需要被轉(zhuǎn)碼了。

babel-register 通過攔截 node require 方法,為 node 運(yùn)行時(shí)引入了 Babel 的轉(zhuǎn)譯能力。

  • babel-loader

babel-loader 是利用 babel-core 的 API 封裝的 webpack loader,用于 webpack 構(gòu)建過程。

  • babel-types

babel-types 是一個(gè)非常強(qiáng)大的工具集合,它集成了節(jié)點(diǎn)校驗(yàn)、增刪改查等功能,是 Babel 核心模塊開發(fā)、插件開發(fā)等場景下不可或缺的工具。

例如:

const t = require('@babel/types');
const binaryExpression = t.binaryExpression('+', t.numericLiteral(1), t.numericLiteral(2));
  • babel-template

模板引擎,負(fù)責(zé)將代碼字符串轉(zhuǎn)為 AST 節(jié)點(diǎn)對象。

import { smart as template } from '@babel/template';
    import generate from '@babel/generator';
    import * as t from '@babel/types';


    const buildRequire = template(      var %%importName%% = require(%%source%%);    );


    const ast = buildRequire({
        importName: t.identifier('myModule'),
        source: t.stringLiteral("my-module"),
    });


    const code = generate(ast).code


    console.log(code)

        運(yùn)行結(jié)果:

var myModule = require("my-module");
  • babel-code-frame

負(fù)責(zé)打印出錯(cuò)的代碼位置,例如:

const { codeFrameColumns } = require('@babel/code-frame');


const testCode = `
class Run {
    constructor() {}
}
`;


const location = {
    start: {
        line: 2,
        column: 2,
    }
};


const result = codeFrameColumns(testCode, location);


console.log(result);
1 | class Run {
> 2 |     constructor() {}
    |  ^
  3 | }
  4 |
  • babel-highlight

向控制臺輸出有顏色的代碼片段。該工具可以識別 JavaScript 中的操作符號、標(biāo)識符、保留字等類型的詞法單元,并在終端環(huán)境下顯示不同的顏色。

運(yùn)行時(shí)相關(guān)模塊

Babel 配合其插件可以對靜態(tài)代碼進(jìn)行轉(zhuǎn)譯,但有一些遺漏點(diǎn):

  • 對于運(yùn)行時(shí)涉及的一些高版本 API,并沒有提供兼容目標(biāo)環(huán)境的 Polyfill。
  • 轉(zhuǎn)譯產(chǎn)物代碼可能有些臃腫。

為此,運(yùn)行時(shí)模塊(runtime)關(guān)注的是轉(zhuǎn)譯產(chǎn)物的運(yùn)行時(shí)環(huán)境,對運(yùn)行時(shí)提供 API polyfill、代碼優(yōu)化等,該模塊涉及幾個(gè)子包:

  • babel-preset-env
  • babel-plugin-transform-runtime
  • babel-runtime
  • babel-runtime-corejs2/3
  • core-js

接下來以案例解釋 runtime 模塊的作用。

源碼文件 index.js 的內(nèi)容:

const a = 1; // const 為語法部分
class Base {} // class 為語法部分
new Promise() // Promise 為 API 部分

這段源碼包含了語法和 API 部分:

  • const、class 為語法部分
  • Promise 為 API 部分

如果希望這段源碼轉(zhuǎn)為 ES5 版本,使構(gòu)建產(chǎn)物可以運(yùn)行在不支持 ES6 和 Promise 的環(huán)境里,該怎么做呢?

用 babel 命令行執(zhí)行轉(zhuǎn)譯,其中源文件為 index.js,轉(zhuǎn)譯產(chǎn)物文件為 index-compiled.js。

npx babel index.js --out-file index-compiled.js

需要配置.babelrc 幫助 Babel 完成語法和 API 部分的轉(zhuǎn)譯:

.babelrc:

{
    "presets": [
        [ 
            "@babel/preset-env"
        ]
    ],
    "plugins": [
        [
            "@babel/plugin-transform-runtime",
            {
                "corejs": 3
            }
        ]
    ]
}

簡要解釋下該配置的原理:

  • babel-preset-env 可以完成語法部分轉(zhuǎn)譯,即 const 轉(zhuǎn)譯為var但構(gòu)建產(chǎn)物中,有些輔助代碼如 _classCallCheck 是以硬編碼的形式直接寫入轉(zhuǎn)譯產(chǎn)物的:
"use strict";


    function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }


    var a = 1;


    var Base = function Base() {
        _classCallCheck(this, Base);
    };


    new Promise();

這樣的后果就是構(gòu)建產(chǎn)物比較臃腫。

  • babel-plugin-transform-runtime 可以將上述 _classCallCheck 置于通用包中,以引用的形式寫入轉(zhuǎn)譯產(chǎn)物:
"use strict";


    var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");


    var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));


    var a = 1;


    var Base = function Base() {
        (0, _classCallCheck2["default"])(this, Base);
    };


    new Promise();
  • babel-plugin-transform-runtime 的配置參數(shù) corejs 用于轉(zhuǎn)譯 API 部分,如 Promsie
"use strict";


    var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");


    var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));


    var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck"));


    var a = 1;


    var Base = function Base() {
        (0, _classCallCheck2["default"])(this, Base);
    };


    new _promise"default";

Babel 轉(zhuǎn)譯過程的運(yùn)行時(shí)優(yōu)化是一個(gè)繁瑣的過程,為此將單獨(dú)用一章講解運(yùn)行時(shí)優(yōu)化,感興趣的同學(xué)可以直接閱讀 "Babel Runtime" 章節(jié)詳細(xì)了解。

三、標(biāo)準(zhǔn)化

Babel 生態(tài)涉及的一些標(biāo)準(zhǔn)化組織。無論是 JavaScript、HTML、DOM、URL 等領(lǐng)域,均需要統(tǒng)一的標(biāo)準(zhǔn),才能在不同的運(yùn)行環(huán)境下有統(tǒng)一的表現(xiàn)。Babel 轉(zhuǎn)譯也需要遵循這些標(biāo)準(zhǔn),包括 ECMAScript、web標(biāo)準(zhǔn)等。

ECMAScript

JavaScript誕生

1995 年,JavaScript 的第一個(gè)版本發(fā)布。用時(shí)間線的方式描述 JavaScript 的誕生過程會更清晰: 

圖片圖片

ECMAScript發(fā)布

1996 年,微軟模仿 JavaScript 實(shí)現(xiàn)了 JScript 并內(nèi)置在 IE3.0,隨后,Netscape 公司著手推動(dòng) JavaScript 標(biāo)準(zhǔn)化。

這里涉及幾個(gè)組織:

  • Ecma International

Ecma International 是一家國際性會員制度的信息和電信標(biāo)準(zhǔn)組織。1994年之前,名為歐洲計(jì)算機(jī)制造商協(xié)會(European Computer Manufacturers Association)。因?yàn)橛?jì)算機(jī)的國際化,組織的標(biāo)準(zhǔn)牽涉到很多其他國家,因此組織決定改名表明其國際性。

Ecma International 的任務(wù)包括與有關(guān)組織合作開發(fā)通信技術(shù)和消費(fèi)電子標(biāo)準(zhǔn)、鼓勵(lì)準(zhǔn)確的標(biāo)準(zhǔn)落實(shí)、和標(biāo)準(zhǔn)文件與相關(guān)技術(shù)報(bào)告的出版。

Ecma International 負(fù)責(zé)多個(gè)國際標(biāo)準(zhǔn)的制定:

  • CD-ROM 格式(之后被國際標(biāo)準(zhǔn)化組織批準(zhǔn)為ISO 9660)
  • C# 語言規(guī)范
  • C++/CLI 語言規(guī)范
  • 通用語言架構(gòu)(CLI)
  • Eiffel 語言
  • 電子產(chǎn)品環(huán)境化設(shè)計(jì)要素
  • Universal 3D 標(biāo)準(zhǔn)
  • OOXML
  • Dart 語言規(guī)范
  • ECMAScript 語言規(guī)范(以 JavaScript 為基礎(chǔ))ECMA-262其中就包括 JavaScript 標(biāo)準(zhǔn)語言規(guī)范 ECMAScript。cma International 擁有 ECMAScript 的商標(biāo)。
  • ECMA TC39

「TC39」全稱「Technical Committee 39」譯為「第 39 號技術(shù)委員會」,是 Ecma International 組織架構(gòu)中的一部分。

TC39 負(fù)責(zé)迭代和發(fā)展 ECMAScript,它的成員由各個(gè)主流瀏覽器廠商的代表組成,通常每年召開約 6 次會議來討論未決提案的進(jìn)展情況,會議的每一項(xiàng)決議必須得到大部分人的贊同,并且沒有人強(qiáng)烈反對才可以通過。

TC39 負(fù)責(zé):

維護(hù)和更新 ECMAScript 語言標(biāo)準(zhǔn)

識別、開發(fā)、維護(hù) ECMAScript 的擴(kuò)展功能庫

開發(fā)測試套件

為 ISO/IEC JTC 1 提供標(biāo)準(zhǔn)

評估和考慮新添加的標(biāo)準(zhǔn)

  • ISO

國際標(biāo)準(zhǔn)化組織(英語: International Organization for Standardization,簡稱: ISO)成立于 1947 年 2 月 23 日,制定全世界工商業(yè)國際標(biāo)準(zhǔn)的國際標(biāo)準(zhǔn)建立機(jī)構(gòu)。

ISO 的國際標(biāo)準(zhǔn)以數(shù)字表示,例如: "ISO 11180:1993" 的 "11180" 是標(biāo)準(zhǔn)號碼,而 "1993" 是出版年份。

ISO/IEC JTC 1 是國際標(biāo)準(zhǔn)化組織和國際電工委員會聯(lián)合技術(shù)委員會。其目的是開發(fā)、維護(hù)和促進(jìn)信息技術(shù)以及信息和通信技術(shù)領(lǐng)域的標(biāo)準(zhǔn)。JTC 1 負(fù)責(zé)了許多關(guān)鍵的 IT 標(biāo)準(zhǔn),從 MPEG 視頻格式到 C++ 編程語言。

圖片圖片

  • ECMAScript 發(fā)展過程中的關(guān)鍵節(jié)點(diǎn)

圖片圖片

ECMAScript 各版本

ECMAScript 經(jīng)歷了多個(gè)版本,每個(gè)版本有自己的特點(diǎn),簡單列舉如下: 

圖片圖片

圖片圖片

ECMAScript 迭代過程

一個(gè) ECMAScript 標(biāo)準(zhǔn)的制作過程,包含了 Stage 0 到 Stage 4 共 5 個(gè)階段,每個(gè)階段提交至下一階段都需要 TC39 審批通過。

圖片圖片

圖片圖片

特性進(jìn)入 Stage-4 后,才有可能被加入標(biāo)準(zhǔn)中,還需要 ECMA General Assembly 表決通過才能進(jìn)入下一次的 ECMAScript 標(biāo)準(zhǔn)中。

如何閱讀 ECMAScript

ECMAScript 文檔結(jié)構(gòu)

ECMAScript 的規(guī)格,可以在 ECMA 國際標(biāo)準(zhǔn)組織的官方網(wǎng)站免費(fèi)下載和在線閱讀。

查看ECMAScript 不同版本的地址:https://ecma-international.org/publications-and-standards/standards/ecma-262/。

截至 2023年底,已發(fā)布的版本如下:

  • ECMA-262 5.1 edition, June 2011

(https://262.ecma-international.org/5.1/index.html)

  • ECMA-262, 6th edition, June 2015

(https://262.ecma-international.org/6.0/index.html)

  • ECMA-262, 7th edition, June 2016

(https://262.ecma-international.org/7.0/index.html)

  • ECMA-262, 8th edition, June 2017

(https://262.ecma-international.org/8.0/index.html)

  • ECMA-262, 9th edition, June 2018

(https://262.ecma-international.org/9.0/index.html)

  • ECMA-262, 10th edition, June 2019

(https://262.ecma-international.org/10.0/index.html)

  • ECMA-262, 11th edition, June 2020

(https://262.ecma-international.org/11.0/index.html)

  • ECMA-262, 12th edition, June 2021

(https://262.ecma-international.org/12.0/index.html)

  • ECMA-262, 13th edition, June 2022

(https://262.ecma-international.org/13.0/index.html)

  • ECMA-262, 14th edition, June 2023

(https://262.ecma-international.org/14.0/index.html)

每個(gè)版本有獨(dú)立的網(wǎng)址,格式為: https://262.ecma-international.org/{version}/,比如 ECMAScript 14.0 版本的網(wǎng)址為 https://262.ecma-international.org/14.0/。

從章節(jié)數(shù)量上,ECMAScript 6.0、ECMAScript 7.0 有 26 章,之后的版本有 27-29 章,雖然章節(jié)數(shù)量不同,規(guī)格章節(jié)的分布是保持一定規(guī)律的,以 ECMAScript 11.0 版本為例:

  • Introduction: 介紹部分

該章節(jié)簡要描述了: JavaScript 和 ECMAScript 的發(fā)展歷史、不同 ECMAScript 規(guī)格的主要更新內(nèi)容。

  • 第 1 章到第 3 章: 描述了規(guī)格文件本身,而非語言

第 1 章用一句話描述了該規(guī)格的描述范圍。

第 2 章描述了基于規(guī)格的"實(shí)現(xiàn)"的一致性要求:

"實(shí)現(xiàn)"必須支持規(guī)格中描述的所有類型、值、對象、屬性、函數(shù)以及程序的語法和語義

"實(shí)現(xiàn)"必須按照 Unicode 標(biāo)準(zhǔn)和 ISO/IEC 10646 的最新版本處理文本輸入

"實(shí)現(xiàn)"如果提供了應(yīng)用程序編程接口(API),那么該 API 需要適應(yīng)不同的人文語言和國家差異,且必須實(shí)現(xiàn)最新版本的 ECMA-402 所定義的與本規(guī)范相兼容的接口

"實(shí)現(xiàn)"可以支持該規(guī)格中沒有提及的類型、值、對象、屬性、函數(shù)、正則表達(dá)式語法以及其他編程寫法

"實(shí)現(xiàn)"不能實(shí)現(xiàn)該規(guī)格中禁止的寫法

  • 第 3 章描述了該規(guī)格的一些參考資料:
  • ISO/IEC 10646
  • ECMA-402
  • EMCA-404 JSON 數(shù)據(jù)交換格式規(guī)范
  • 第 4 章: 對這門語言總體設(shè)計(jì)的描述。
  • 第 5 章到第 8 章: 語言宏觀層面的描述。
  • 第 6 章介紹數(shù)據(jù)類型。
  • 第 7 章介紹語言內(nèi)部用到的抽象操作。
  • 第 8 章介紹代碼如何運(yùn)行。
  • 第 9 章到第 27 章: 介紹具體的語法。

一般而言,除非寫編譯器,開發(fā)者無需閱讀 ECMAScript 的規(guī)格,規(guī)格的內(nèi)容非常多,如無必要也無需通讀。只是在遇到一些奇怪的問題時(shí),閱讀官方規(guī)格,是最穩(wěn)妥的辦法。

通過閱讀規(guī)格解決一些問題

(以ECMAScript 11.0為例)

  • 識別關(guān)鍵詞和保留字,并高亮

Babel 工具集中的 babel-highlight,可以實(shí)現(xiàn)在終端對代碼塊中的目標(biāo)字符單元顯示不同的顏色。這里需要識別不同字符單元的類型,如關(guān)鍵字、保留字、標(biāo)識符、數(shù)字、字符串等。

標(biāo)識符、數(shù)字、字符串都很好理解和識別,但哪些字符應(yīng)該被識別為關(guān)鍵字、保留字,而不是標(biāo)識符呢?

此時(shí)可以閱讀 ECMAScript 規(guī)格了,ECMAScript 11.0 規(guī)格的 11.6.2 節(jié)介紹了關(guān)鍵詞和保留字列表。

關(guān)鍵詞(keywords)關(guān)鍵詞首先是標(biāo)識符,同時(shí)有語義,包括 if、while、async、await...,個(gè)別關(guān)鍵詞是可以用作變量名的。

保留字(reserved word)保留字首先是標(biāo)識符,但不能用作變量名。部分關(guān)鍵詞是保留字,但部分不是: if、while是保留字;await只有在 async方法和模塊中才是保留字;async不是保留字,它可以作為普通的變量名使用。

保留字列表

await
break
case
catch
class
const
continue
debugger
default
delete
do
else
enum
export
extends
false
finally
for
function
if
import
in
instanceof
new
null
returns
uper
switch
this
throw
true
try
typeof
var
void
while
with
yield

讀完上述規(guī)格,也就知道哪些字符單元是需要識別為保留字與關(guān)鍵詞,并高亮的了。

  • 識別全局對象,并高亮

繼續(xù)使用 babel-highlight 實(shí)現(xiàn)代碼塊中的全局對象高亮,那么,我們需要知道哪些是規(guī)格中描述的全局變量。

規(guī)格的 18 章介紹了全局對象,通過該章的描述,可以知道: 

全局屬性全局屬性有: globalThis、Infinity、NaN、undefined。

全局方法

全局方法有: eval(x)、isFinite、isNaN、parseFloat、parseInt、decodeURIComponent、encodeURIComponent 等。

  • 全局構(gòu)造函數(shù)

全局的構(gòu)造函數(shù)有: 

Array
ArrayBuffer
BigInt
BigInt64Array
BigUnit64Array
Boolean
DataView
Date
Error
EvalError
Float32Array
Float64Array
Function
Int8Array
Int16Array
Int32Array
Map
Number
Object
Promise
Proxy
RangeError
ReferenceError
RegExp
Set
SharedArrayBuffer
String
Symbol
SyntaxError
TypeError
Uint8Array
Uint8ClampedArray
Uint16Array
Uint32Array
URIError
WeakMap
WeakSet

其他的全局屬性Atomics、JSON、Math、Reflect。很顯然,當(dāng)字符單元的名稱是上述名稱中的一員時(shí),我們可以對其進(jìn)行高亮處理了(若上下文中無重新定義的同名變量)。

  • 自定義 Error

babel-loader 自身維護(hù)了私有的 LoaderError 對象,該對象繼承自原生 Error 類,并且訂制了部分實(shí)例屬性。代碼如下: 

class LoaderError extends Error {
    constructor(err) {
        super();


        const { name, message, codeFrame, hideStack } = format(err);


        this.name = "BabelLoaderError";


        this.message = ${name ? ${name}: ` : ""}${message}\n\n${codeFrame}\n`;


        this.hideStack = hideStack;


        Error.captureStackTrace(this, this.constructor);
    }
}

可以看到,babel-loader 自定義了錯(cuò)誤實(shí)例的 name、message、hideStack 屬性,那么,問題是,原生的 Error 類有哪些屬性和方法,哪些是開發(fā)者可以自定義的呢?

規(guī)格的 19.5 章節(jié),詳細(xì)介紹了 Error 的各類規(guī)范:

Error 作為函數(shù)被調(diào)用時(shí)(Error(...)),表現(xiàn)和 new Error(...) 一致,均會創(chuàng)建并返回 Error 的新實(shí)例

Error 可以被繼承,比如通過 extends 的方式,子類必須提供 constructor 方法,且該方法內(nèi)必須提供 super() 調(diào)用

Error 構(gòu)造函數(shù)必須有 prototype 屬性

Error.prototype 屬性需有以下屬性:

Error.prototype.constructor: 指向構(gòu)造函數(shù)

Error.prototype.message: 描述錯(cuò)誤信息,默認(rèn)是空字符串

Error.prototype.name: 描述錯(cuò)誤名稱,默認(rèn)值是 Error

從 LoaderError 的源碼可以看到,LoaderError 做了以下幾件事情:

  • LoaderError 繼承自 Error
  • 實(shí)例自定義了 name、message 屬性,明確 babel-loader 的信息
  • 實(shí)例自定義的 hideStack 屬性是非標(biāo)準(zhǔn)屬性,用于 babel-loader 內(nèi)部

web標(biāo)準(zhǔn)

是在解決 API Polyfil 的時(shí)候,Babel 配合使用的 core-js 除了提供 ECMAScript 標(biāo)準(zhǔn)下的 JavaScript API 實(shí)現(xiàn),也提供了 DOM/URL 等實(shí)現(xiàn)。而 DOM/URL 所屬的 web 標(biāo)準(zhǔn),由 W3C/WHATWG 制定。

圖片圖片

經(jīng)過多年發(fā)展,WHATWG 和 W3C 目前是合作關(guān)系,其中,WHATWG 維護(hù) HTML 和 DOM 標(biāo)準(zhǔn),W3C 使用 WHATWG 存儲庫中的 HTML 和 DOM 標(biāo)準(zhǔn)描述,W3C 在 HTML 部分的工作集中在 XHTML/XML 上。

圖片圖片

四、總結(jié)

本文介紹了 Babel 的概述/微內(nèi)核架構(gòu)/ECMAScript標(biāo)準(zhǔn)化方面的設(shè)計(jì)思想和部分實(shí)現(xiàn)原理。

上述內(nèi)容其實(shí)在很早之前就已經(jīng)成型了,筆者也查看了Babel最近的迭代內(nèi)容,發(fā)現(xiàn)并沒有太大的變化。至于代碼轉(zhuǎn)譯領(lǐng)域,目前是Babel還是其他工具哪個(gè)更有優(yōu)勢,不在本文的討論范圍內(nèi)。除了比較社區(qū)哪些工具更好而言,“Babel的設(shè)計(jì)思路、其與標(biāo)準(zhǔn)規(guī)范是怎么配合的”等也是很值得學(xué)習(xí)的地方,也是這篇文章的產(chǎn)生背景。

責(zé)任編輯:武曉燕 來源: 得物技術(shù)
相關(guān)推薦

2021-05-19 07:56:26

Linux內(nèi)核搶占

2017-08-15 13:05:58

Serverless架構(gòu)開發(fā)運(yùn)維

2023-11-29 09:57:23

微服務(wù)容器

2024-05-30 09:07:20

2023-06-07 15:34:21

架構(gòu)層次結(jié)構(gòu)

2021-12-09 08:09:31

Linux內(nèi)核臟頁

2021-07-26 07:47:36

數(shù)據(jù)庫

2023-11-13 16:33:46

2018-12-27 12:34:42

HadoopHDFS分布式系統(tǒng)

2018-04-16 11:04:23

HBaseRegion Serv數(shù)據(jù)庫

2019-03-18 09:50:44

Nginx架構(gòu)服務(wù)器

2022-01-14 12:28:18

架構(gòu)OpenFeign遠(yuǎn)程

2024-06-28 10:25:18

2010-06-01 15:25:27

JavaCLASSPATH

2016-12-08 15:36:59

HashMap數(shù)據(jù)結(jié)構(gòu)hash函數(shù)

2020-07-21 08:26:08

SpringSecurity過濾器

2021-07-05 06:51:45

Linux內(nèi)核調(diào)度器

2021-07-02 06:54:44

Linux內(nèi)核主調(diào)度器

2021-07-20 08:02:41

Linux進(jìn)程睡眠

2012-02-14 10:29:02

Java
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 亚洲国产成人av好男人在线观看 | 天天av综合| 97人人超碰 | 国产人成精品一区二区三 | 久久久国产一区二区三区 | 中文字幕第一页在线 | 国产剧情一区 | 久久99精品视频 | 久久网一区二区三区 | 欧美精品在线一区二区三区 | 综合婷婷| 亚洲有码转帖 | 午夜爽爽爽男女免费观看影院 | 在线观看国产www | 日韩在线播放第一页 | 91看片在线 | 欧美日韩中文字幕在线 | 亚洲小说图片 | 国产精品免费在线 | 蜜臀久久99精品久久久久久宅男 | 国产一区二区三区久久久久久久久 | 欧美成人一区二区 | 欧美久久一区二区 | 中文字幕亚洲国产 | 国产成人精品一区二区三区在线观看 | 久久精品亚洲精品国产欧美 | 国产精品伦理一区二区三区 | 91免费电影 | 欧美大片在线观看 | 午夜精品久久久久久久星辰影院 | 欧美手机在线 | 黑人一级黄色大片 | 在线看无码的免费网站 | 成人免费看片 | 色天天综合 | 欧美视频在线播放 | 最新超碰 | 一区二区视频在线 | 久久久久久久久久久久久9999 | 久久精品这里 | 一区二区三区四区在线视频 |