深入理解 Babel - 微内核架构与 ECMAScript 标准化|得物技术

随着浏览器版本的持续更新,浏览器对JavaScript的支持越来越强大,Babel的重要性显得较低了。但Babel的设计思路、背后依赖的ECMAScript标准化思想仍然值得借鉴。

本文涉及的Babel版本主要是V7.16及以下,截至发文时,Babel最新发布的版本是V7.25.6,未出现大版本更新,近2年也进入了稳定迭代期,本文的分析思路基本适用目前的Babel设计。

一、Babel简介

Babel是什么

Babel是JavaScript转译器,通过Babel,开发者可以自由使用下一代ECMAScript 语法。高版本ECMAScript语法将被转译为低版本语法,以便顺利运行在各类环境,如低版本浏览器、低版本 Node.js 等。

Babel 是转译器,不是编译器。下面是转译和编译的区别:

编译,一般指将一种语言转换为另一种语法和抽象程度等都不同的语言,常见的比如 gcc 编译器。

转译,一般指将一种语言转换为不同版本或者抽象程度相同的语言,比如 Babel 可以把 ECMAScript 6 语法转译为 ECMAScript 5语法。

利用 Babel,开发者可以使用 ECMAScript 的各种新特性进行开发,同时花极少的精力关注浏览器或其他JS运行环境对新特性的支持。甚至,开发者可以根据自身需要,创造属于自己的 JavaScript 语法。

Babel在转译的时候,会对源码进行以下处理: 语法转译(Syntax)和添加API Polyfill。

01.jpg

  • 语法(Syntax)部分
    Babel 支持识别高版本语法,并通过插件将源码从高版本语法转译为低版本语法,如:

    • 箭头函数 () => {} 转为普通函数 function() {}。

    • const / let 转译为var

  • API Polyfill

有些运行时相关的 API,语法转译无法解决它们对低版本浏览器等环境的兼容性问题,因此 Babel 通过与 core-js 等工具的配合,实现 API 部分对目标环境(通常是低版本浏览器等)的兼容。

例如[1, 2, 3].include、Promise等 API,Babel 在处理时,如果目标环节可能不支持原生的 include / Promise 的话,Babel 会在转译结果中嵌入 include / Promise 的自定义实现。

有多种方式可以使用 Babel,如: 命令行(babel-cli、babel-node)、浏览器(babel-standalone)、API 调用(babel-core)、webpack loader(babel-loader)等。

转译过程

和多数转译器相同,Babel 运行的生命周期主要是 3 个阶段: 解析、转换、代码生成。

这个过程涉及抽象语法树:

抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。

AST 是树形对象,以结构化的形式表示编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。

02.jpg

源码字符串需要经转译器生成 AST,转译器有很多种,不同转译器,生成的AST对象格式细节可能有差异,但共同点为: 都是树形对象、该树形对象描述了节点特征、各节点之间的关系(兄弟、父子等)。

以下是 Babel 生命周期的三个过程:

  • 解析(Parsing): Code1 ==> 抽象语法树1
    解析过程包括 2 个环节: 词法解析、语法解析,最终生成抽象语法树。
    词法解析阶段,代码字符串被解析为 token 令牌数组,数组项是一个对象,包括: 代码字符碎片的值、位置、类型等信息。
    token 数组是平铺式的数组,没有嵌套的结构信息,它是为语法解析阶段做准备的。
    语法解析阶段,token 令牌数组被解析为结构化的抽放语法树对象(AST)。
    babel-parser 完成该阶段的主要功能。

03.jpg

  • 转换(Transformation): AST1 ==> AST2
    Babel 生成 AST 后,会对 AST 进行遍历,遍历过程中,各类插件对原 AST 对象进行增删改查等操作,AST 结构被修改。

04.jpg

  • 代码生成(Generation): AST2 ==> Code2
    Babel 将修改后的 AST 对象转目标代码字符串。
    babel-generator 完成该阶段的主要功能。

05.jpg

二、Babel微内核架构

微内核架构

Babel 采用微内核架构,其内核保留核心功能,其余功能利用外部工具和插件机制实现,也体现了"开放-封闭"的设计原则。

06.jpg

除了微内核设计架构,Babel 的模块设计也可以做如下分类:

07.jpg

转译模块

转译模块位于 Babel 微内核架构的"微内核"部分,该部分主要负责代码转译,也就是上面提到的"解析-转换-代码生成"过程。

该模块主要包括: babel-parser、babel-traverse、babel-generator。

  • babel-parser
    负责将代码字符串转为 AST 对象。
    有 2 点值得一提:

    • babel-parser 本身并不会对 AST 做转换操作,只是负责解析出 AST。AST 转换部分交由各类 plugins 和 presets 处理。

    • babel-parser 内置了对 ESNext/TypeScript/JSX/Flow 最新版本语法的支持,但很多默认是不开启的,目前没有开放插件机制扩展新语法。

  • babel-traverse
    在转译过程中,babel-traverse 负责遍历 AST 节点,并根据配置的 plugins/presets,在遍历过程中,对各个 AST 节点进行增删改查的操作。
    AST 是一个树形对象,遍历 AST 对象的过程也是一个深度优先遍历的过程。

  • babel-generator
    负责将 AST 节点,转为代码字符串,同时也可以生成 source-map。

插件模块

插件模块包括 plugins、presets。

  • plugins
    丰富的插件,帮助 Babel 成为一个非常成功的转译工具。
    对 AST 的遍历、转换是 Babel 转译的核心功能,但 Babel 本身并不参与该过程,将这些功能作为插件引入到运行时。
    具体来说,babel-core 作为核心工具,不提供对 AST 的修改逻辑,通过调用各类插件,实现对 AST 的修改。
    Babel的插件分为语法插件和转换插件。

    • 语法插件
      值得注意的是,babel-parser 负责将 JavaScript 代码解析出抽象语法树(AST),它支持全面识别 ESNext/TypeScript/JSX/Flow 等语法,目前由 Babel 团队开发维护,不支持插件化。
      Babel 插件生态中的语法插件,其功能就是作为"开关",配置是否开启 babel-parser 的某些语法转译功能。
      语法插件在 Babel 源码中,以 babel-plugin-syntax 开头。
      举个例子:

      • babel-plugin-syntax-decorators
        负责开启 babel-parser 对装饰器的语法支持。

      • babel-plugin-syntax-dynamic-import
        负责开启 babel-parser 对 import 语句的语法支持。

      • babel-plugin-syntax-jsx
        负责开启 babel-parser 对 jsx 语法的支持。

    • 转换插件
      转换插件就是社区里常说的 Babel 插件,负责转换 AST 节点。
      在介绍babel-traverse时提到,它负责遍历AST对象,每个AST节点会被访问到,等待转换,转换的部分,由"转换插件"负责。
      转换插件会提供一个叫做"Visitor"的对象,该对象的 Key 为节点名称,Value 部分提供进入该节点时、离开该节点时的回调函数,在回调函数里,可以对该节点进行一系列操作。
      “Visitor” 又称为 “访问者”。

// plugin 提供 visitor,在 visitor 中对 AST 节点操作
const visitor = {
    Program: {
        enter() {},
        exit() {},
    },

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

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

转换插件在Babel源码中,以 babel-plugin-transform 开头。

举个例子:

  • babel-plugin-transform-strict-mode

该插件拦截 Program 节点,也就是整个程序的根节点,添加 "use strict"指令。

visitor 节点值为函数时,是 enter 回调的快捷方式。

{
    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

该插件负责拦截函数调用表达式节点 CallExpression,将 Object.assign 转为 extends 写法。

{
    name: "transform-object-assign",

    visitor: {
      CallExpression(path, file) {
        if (path.get("callee").matchesPattern("Object.assign")) {
          path.node.callee = file.addHelper("extends");
        }
      },
    },
}
  • Presets

Babel 插件的功能是细粒度的,大部分插件承担了单一功能。

而在实际开发过程中,往往需要支持对各类语法的支持。此时,有两种做法:

A. 需要支持哪些特性,就分别引入支持该特性的插件

B. 直接引入一个插件集合,涵盖所需的各类插件功能

很显然,第一种做法是相对麻烦的。针对第二种做法,Babel提供了插件集 preset。

preset 在 Babel 源码中,以 babel-preset 开头。

例如,Babel 已经提供了几种常用的 preset 供开发者使用:

  1. babel-preset-env
  2. babel-preset-react
  3. babel-preset-flow
  4. babel-preset-typescript
  • 插件运行顺序 Babel 配置项中,plugins 和 presets 均以数组的形式配置,执行时有先后顺序。

    • plugins 在 presets之前运行

    • plugins 按照数组正序执行

    • presets 按照数组倒序执行

08.jpg

工具模块

工具模块提供 Babel 相关模块所需的各类工具,以下一一简要介绍:

  • babel-core
    babel-core 对外提供了 Babel 多项功能的 API,如转译文件、转译代码、创建/获取配置等,在 Babel 官方文档介绍的比较详细,不再赘述。
    值得注意的是,转译类的 API 均提供了同步和异步版本,如 transformSync/transfomAsync、parseSync/parseAsync。

  • babel-cli
    Babel 的命令行工具,可以直接转译文件夹/文件,它也提供了很多配置项做其他工作,官方文档介绍的比较详细,感兴趣的同学可以去 Babel 官网查看详细配置。

  • babel-standalone
    Babel 对外服务的很多包是基于 node 环境下使用的,babel-standalone 提供了浏览器下转译的方案。
    babel-standalone 内置了所有 Babel 插件,所以体积还是比较大的,而且在浏览器端转译需要时间,比较适合开发、学习使用,不适合在生产环境使用。

举个例子:

<!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>

在浏览器运行该 html,可以看到,页面结构变成了:

<!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
    提供在命令行执行高级语法的环境。

例如:

// index.js 里可以使用高级语法     
babel-node -e index.js

index.js 文件以及被其引入的其他文件均可以使用高级语法了。和 babel-cli 不同的是,babel-cli 只负责转换,不在 node 运行时执行;babel-node 会在 node 运行时执行转换,不适合生产环境使用。

  • babel-register

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

index.js

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

run.js

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

执行 node index 时,run.js 就不需要被转码了。

babel-register 通过拦截 node require 方法,为 node 运行时引入了 Babel 的转译能力。

  • babel-loader

babel-loader 是利用 babel-core 的 API 封装的 webpack loader,用于 webpack 构建过程。

  • babel-types

babel-types 是一个非常强大的工具集合,它集成了节点校验、增删改查等功能,是 Babel 核心模块开发、插件开发等场景下不可或缺的工具。

例如:

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

模板引擎,负责将代码字符串转为 AST 节点对象。

    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)

运行结果:

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

负责打印出错的代码位置,例如:

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 中的操作符号、标识符、保留字等类型的词法单元,并在终端环境下显示不同的颜色。

运行时相关模块

Babel 配合其插件可以对静态代码进行转译,但有一些遗漏点:

  • 对于运行时涉及的一些高版本 API,并没有提供兼容目标环境的 Polyfill。

  • 转译产物代码可能有些臃肿。

为此,运行时模块(runtime)关注的是转译产物的运行时环境,对运行时提供 API polyfill、代码优化等,该模块涉及几个子包:

  • babel-preset-env

  • babel-plugin-transform-runtime

  • babel-runtime

  • babel-runtime-corejs2/3

  • core-js

接下来以案例解释 runtime 模块的作用。

源码文件 index.js 的内容:

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

这段源码包含了语法和 API 部分:

  • const、class 为语法部分

  • Promise 为 API 部分

如果希望这段源码转为 ES5 版本,使构建产物可以运行在不支持 ES6 和 Promise 的环境里,该怎么做呢?

用 babel 命令行执行转译,其中源文件为 index.js,转译产物文件为 index-compiled.js。

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

需要配置.babelrc 帮助 Babel 完成语法和 API 部分的转译:

.babelrc:

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

简要解释下该配置的原理:

  • babel-preset-env 可以完成语法部分转译,即 const 转译为var
    但构建产物中,有些辅助代码如 _classCallCheck 是以硬编码的形式直接写入转译产物的:
"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();

这样的后果就是构建产物比较臃肿。

  • babel-plugin-transform-runtime 可以将上述 _classCallCheck 置于通用包中,以引用的形式写入转译产物:
"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 的配置参数 corejs 用于转译 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 转译过程的运行时优化是一个繁琐的过程,为此将单独用一章讲解运行时优化,感兴趣的同学可以直接阅读 “Babel Runtime” 章节详细了解。

三、标准化

Babel 生态涉及的一些标准化组织。无论是 JavaScript、HTML、DOM、URL 等领域,均需要统一的标准,才能在不同的运行环境下有统一的表现。Babel 转译也需要遵循这些标准,包括 ECMAScript、web标准等。

ECMAScript

JavaScript诞生

1995 年,JavaScript 的第一个版本发布。用时间线的方式描述 JavaScript 的诞生过程会更清晰:

09.jpg

ECMAScript发布

1996 年,微软模仿 JavaScript 实现了 JScript 并内置在 IE3.0,随后,Netscape 公司着手推动 JavaScript 标准化。

这里涉及几个组织:

  • Ecma International
    Ecma International 是一家国际性会员制度的信息和电信标准组织。1994年之前,名为欧洲计算机制造商协会(European Computer Manufacturers Association)。因为计算机的国际化,组织的标准牵涉到很多其他国家,因此组织决定改名表明其国际性。
    Ecma International 的任务包括与有关组织合作开发通信技术和消费电子标准、鼓励准确的标准落实、和标准文件与相关技术报告的出版。
    Ecma International 负责多个国际标准的制定:

    • CD-ROM 格式(之后被国际标准化组织批准为ISO 9660)

    • C# 语言规范

    • C++/CLI 语言规范

    • 通用语言架构(CLI)

    • Eiffel 语言

    • 电子产品环境化设计要素

    • Universal 3D 标准

    • OOXML

    • Dart 语言规范

    • ECMAScript 语言规范(以 JavaScript 为基础)ECMA-262
      其中就包括 JavaScript 标准语言规范 ECMAScript。
      cma International 拥有 ECMAScript 的商标。

  • ECMA TC39
    「TC39」全称「Technical Committee 39」译为「第 39 号技术委员会」,是 Ecma International 组织架构中的一部分。
    TC39 负责迭代和发展 ECMAScript,它的成员由各个主流浏览器厂商的代表组成,通常每年召开约 6 次会议来讨论未决提案的进展情况,会议的每一项决议必须得到大部分人的赞同,并且没有人强烈反对才可以通过。
    TC39 负责:

    • 维护和更新 ECMAScript 语言标准

    • 识别、开发、维护 ECMAScript 的扩展功能库

    • 开发测试套件

    • 为 ISO/IEC JTC 1 提供标准

    • 评估和考虑新添加的标准

  • ISO

国际标准化组织(英语: International Organization for Standardization,简称: ISO)成立于 1947 年 2 月 23 日,制定全世界工商业国际标准的国际标准建立机构。

ISO 的国际标准以数字表示,例如: “ISO 11180:1993” 的 “11180” 是标准号码,而 “1993” 是出版年份。

ISO/IEC JTC 1 是国际标准化组织和国际电工委员会联合技术委员会。其目的是开发、维护和促进信息技术以及信息和通信技术领域的标准。JTC 1 负责了许多关键的 IT 标准,从 MPEG 视频格式到 C++ 编程语言。

10.jpg

  • ECMAScript 发展过程中的关键节点

11.jpg

ECMAScript 各版本

ECMAScript 经历了多个版本,每个版本有自己的特点,简单列举如下:

12.jpg

13.jpg

ECMAScript 迭代过程

一个 ECMAScript 标准的制作过程,包含了 Stage 0 到 Stage 4 共 5 个阶段,每个阶段提交至下一阶段都需要 TC39 审批通过。

14.jpg

15.jpg

特性进入 Stage-4 后,才有可能被加入标准中,还需要 ECMA General Assembly 表决通过才能进入下一次的 ECMAScript 标准中。

如何阅读 ECMAScript

ECMAScript 文档结构

ECMAScript 的规格,可以在 ECMA 国际标准组织的官方网站免费下载和在线阅读。

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

截至 2023年底,已发布的版本如下:

  • 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)

每个版本有独立的网址,格式为: https://262.ecma-international.org/{version}/,比如 ECMAScript 14.0 版本的网址为 https://262.ecma-international.org/14.0/。

从章节数量上,ECMAScript 6.0、ECMAScript 7.0 有 26 章,之后的版本有 27-29 章,虽然章节数量不同,规格章节的分布是保持一定规律的,以 ECMAScript 11.0 版本为例:

  • Introduction: 介绍部分

该章节简要描述了: JavaScript 和 ECMAScript 的发展历史、不同 ECMAScript 规格的主要更新内容。

  • 第 1 章到第 3 章: 描述了规格文件本身,而非语言

    • 第 1 章用一句话描述了该规格的描述范围。

    • 第 2 章描述了基于规格的"实现"的一致性要求:

      • "实现"必须支持规格中描述的所有类型、值、对象、属性、函数以及程序的语法和语义

      • "实现"必须按照 Unicode 标准和 ISO/IEC 10646 的最新版本处理文本输入

      • "实现"如果提供了应用程序编程接口(API),那么该 API 需要适应不同的人文语言和国家差异,且必须实现最新版本的 ECMA-402 所定义的与本规范相兼容的接口

      • "实现"可以支持该规格中没有提及的类型、值、对象、属性、函数、正则表达式语法以及其他编程写法

      • "实现"不能实现该规格中禁止的写法

  • 第 3 章描述了该规格的一些参考资料:

    • ISO/IEC 10646

    • ECMA-402

    • EMCA-404 JSON 数据交换格式规范

  • 第 4 章: 对这门语言总体设计的描述。

  • 第 5 章到第 8 章: 语言宏观层面的描述。

  • 第 6 章介绍数据类型。

  • 第 7 章介绍语言内部用到的抽象操作。

  • 第 8 章介绍代码如何运行。

  • 第 9 章到第 27 章: 介绍具体的语法。

一般而言,除非写编译器,开发者无需阅读 ECMAScript 的规格,规格的内容非常多,如无必要也无需通读。只是在遇到一些奇怪的问题时,阅读官方规格,是最稳妥的办法。

通过阅读规格解决一些问题(以ECMAScript 11.0为例)

  • 识别关键词和保留字,并高亮
    Babel 工具集中的 babel-highlight,可以实现在终端对代码块中的目标字符单元显示不同的颜色。这里需要识别不同字符单元的类型,如关键字、保留字、标识符、数字、字符串等。
    标识符、数字、字符串都很好理解和识别,但哪些字符应该被识别为关键字、保留字,而不是标识符呢?
    此时可以阅读 ECMAScript 规格了,ECMAScript 11.0 规格的 11.6.2 节介绍了关键词和保留字列表。

    • 关键词(keywords)
      关键词首先是标识符,同时有语义,包括 if、while、async、await…,个别关键词是可以用作变量名的。

    • 保留字(reserved word)
      保留字首先是标识符,但不能用作变量名。
      部分关键词是保留字,但部分不是: 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

读完上述规格,也就知道哪些字符单元是需要识别为保留字与关键词,并高亮的了。

  • 识别全局对象,并高亮
    继续使用 babel-highlight 实现代码块中的全局对象高亮,那么,我们需要知道哪些是规格中描述的全局变量。
    规格的 18 章介绍了全局对象,通过该章的描述,可以知道:

    • 全局属性
      全局属性有: globalThis、Infinity、NaN、undefined。

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

      • 全局构造函数
        全局的构造函数有:

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。
    很显然,当字符单元的名称是上述名称中的一员时,我们可以对其进行高亮处理了(若上下文中无重新定义的同名变量)。

  • 自定义 Error
    babel-loader 自身维护了私有的 LoaderError 对象,该对象继承自原生 Error 类,并且订制了部分实例属性。代码如下:


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 自定义了错误实例的 name、message、hideStack 属性,那么,问题是,原生的 Error 类有哪些属性和方法,哪些是开发者可以自定义的呢?

规格的 19.5 章节,详细介绍了 Error 的各类规范:

  • Error 作为函数被调用时(Error(…)),表现和 new Error(…) 一致,均会创建并返回 Error 的新实例

  • Error 可以被继承,比如通过 extends 的方式,子类必须提供 constructor 方法,且该方法内必须提供 super() 调用

  • Error 构造函数必须有 prototype 属性

    • Error.prototype 属性需有以下属性:

      • Error.prototype.constructor: 指向构造函数

      • Error.prototype.message: 描述错误信息,默认是空字符串

      • Error.prototype.name: 描述错误名称,默认值是 Error

从 LoaderError 的源码可以看到,LoaderError 做了以下几件事情:

  • LoaderError 继承自 Error

  • 实例自定义了 name、message 属性,明确 babel-loader 的信息

  • 实例自定义的 hideStack 属性是非标准属性,用于 babel-loader 内部

web标准

是在解决 API Polyfil 的时候,Babel 配合使用的 core-js 除了提供 ECMAScript 标准下的 JavaScript API 实现,也提供了 DOM/URL 等实现。而 DOM/URL 所属的 web 标准,由 W3C/WHATWG 制定。

16.jpg

经过多年发展,WHATWG 和 W3C 目前是合作关系,其中,WHATWG 维护 HTML 和 DOM 标准,W3C 使用 WHATWG 存储库中的 HTML 和 DOM 标准描述,W3C 在 HTML 部分的工作集中在 XHTML/XML 上。

17.jpg

总结

本文介绍了 Babel 的概述/微内核架构/ECMAScript标准化方面的设计思想和部分实现原理。

上述内容其实在很早之前就已经成型了,笔者也查看了Babel最近的迭代内容,发现并没有太大的变化。至于代码转译领域,目前是Babel还是其他工具哪个更有优势,不在本文的讨论范围内。除了比较社区哪些工具更好而言,“Babel的设计思路、其与标准规范是怎么配合的”等也是很值得学习的地方,也是这篇文章的产生背景。

希望本文对你有所帮助!

*文 / hoperyy

本文属得物技术原创,更多精彩文章请看:得物技术

未经得物技术许可严禁转载,否则依法追究法律责任!

相关推荐

压测AI Agent 治理与评测调优实践|得物技术

本文介绍智能分析Agent在压测调试中上线后的治理闭环建设:通过Langfuse记录完整执行链路,结合用户反馈与Trace还原问题根因;利用CLI Mock固化证据数据集,实现相同场景下的回测验证。基于固定案例与五档评分机制,持续评估方案质量、延迟与成本,确保修复有效且无新问题引入,推动Agent能力迭代优化。

SmartCodeTech的博客 310

从中心调度到自驱协作多 Agent 架构的三次反转|得物技术

本文探讨多Agent系统中的控制权分配问题,提出三大协作架构:Master Agent(中心调度)、任务看板(共享状态)与Advisor(轻量咨询)。通过划清上下文边界与模型边界,强调应以信息相关性而非职业标签划分Agent。三种模式分别将决策权集中于中心、下放至共享状态、再下沉至执行者,形成控制权逐步下沉的演进路径。案例显示,合理设计可提升复杂任务的并行性、弹性与可维护性。

SmartCodeTech的博客 420

Jev 实战:为AI工作流引入轻量决策层 x10倍提速|得物技术

完成这三个场景后,我对适用边界有了更明确的认识:它们都可以先定义答案范围,再根据判断结果驱动下一步操作。接入时,我会优先明确输入、选项、采纳条件和兜底路径,再评估Jev是否适合承担这一环节。结合这些实践,我更容易理解Jev(TypeSafe System One)作为专用结构化决策模型不生成自然语言,而是返回带概率的判断结果。后续接入时,我会继续从脚本中边界明确的判断任务开始,分别验证准确性、耗时和费用,再决定是否扩大使用范围。下面整理了相关能力、限制和接入要点,便于查阅。

SmartCodeTech的博客 345

国产算力·昇腾 910C 大模型推理优化(下):源码修改与算子优化,提速30%|得物技术

本文延续上篇,深入vllm-ascend源码优化:通过多流重叠实现MoE共享专家并行计算,消除冗余事件开销,并解除与FUSED_MC2的互斥限制,实现c=1下TPOT从8.2ms降至8.0ms;优化decode阶段host侧开销,引入状态跟踪跳过冗余拷贝;设计Block Table CPU快路径,规避小batch下NPU kernel启动延迟;针对GDN层融合L2Norm至recurrent kernel,减少算子调用与内存往返。综合优化后推理性能显著提升,形成可复用的昇腾910C大模型推理优化方法论。

SmartCodeTech的博客 245

国产算力·昇腾 910C 大模型推理优化(上):镜像更新与参数调优,提速 40%|得物技术

文中详细给出每一项优化的动机、实现(含具体源码改动路径与关键代码片段)、验证数据与踩坑记录(包括十余项实测无效或负向的尝试),希望为同样在国产算力上做推理优化的团队提供一份可直接复用的工程参考。

SmartCodeTech的博客 225

动态规则的 Agent 实践:用确定性工程驾驭 LLM 的资产智能验收

面对财务验收中规则多变、材料非结构化、核对复杂等痛点,传统规则引擎难以应对。系统采用“规则即配置”思路,由大语言模型(LLM)负责理解合同、扫描件等非结构化材料并执行语义比对,工程系统则保障流程编排与可追溯性。通过异步处理、幂等设计、三类流量隔离及双通道(文本/图像)处理,实现高效稳定运行。结合用户反馈构建自动标准答案,辅以试跑、回测与发布门禁机制,形成闭环质量体系。底层采用确定性工作流架构,确保行为可预期、可测试,真正实现灵活规则的快速迭代与安全上线。

SmartCodeTech的博客 344

发一张图,它居然“跃“出屏幕了?一文读懂得物 3D 空间图片技术实践

3D 空间图片功能的落地,涉及模型生成、内容分发、客户端渲染之间的一系列取舍。本文重点分享如何生产出高质量、小体积的模型,以及如何在手机上流畅运行。

SmartCodeTech的博客 555

别再只卷向量检索了,得物交易搜索如何用“生成式”实现召回范式跃迁?

你搜"af1",它得给你"空军一号"。这一年,得物交易搜索把召回从"做选择题"改成了"写答案"——不再从商品池里"找"最像的,而是让模型自己"生成"你真正想要的。从 LLM 语义索引到 HLLM、语义 ID,搜索是怎么从"检索"走向"生成"的?

SmartCodeTech的博客 594

指标平台:从语义底座到智能消费的实践路径|得物技术

这篇文章想做的,不是在本体化的宏大叙事上再叠加一层理论,而是把我们在真实落地中验证过的路径讲清楚:语义底座怎么从零建立起来、怎么保证质量不失控、怎么支撑 Text2SQL 和 AI Coding 两条消费主线,以及沿着这条路径往前走,下一步该往哪个方向发力。

SmartCodeTech的博客 317

企业级 MultiAgent 落地:Plan 模式与主子 Agent 协作|得物技术

基于 AgentScope Java 的企业级 MultiAgent 平台,为研发、数据分析和知识问答等场景提供统一的模型调用、工具接入、任务编排、流式输出与运行追踪能力。

SmartCodeTech的博客 302

得物小摊 AI Native 演进实录:用 Harness 构建可控 AI 交付

AI Coding 一个人用很顺手,进了团队就漏:指令没人审、经验难沉淀、过程看不见、链路不闭环。作者团队基于 Multica 做了 EP-Harness,把 Agent 当成员管,给它套一层可执行、可观察、可治理的 Harness,并让反馈闭环。成果:可追溯决策、多 Agent 协作,高频异常从每 4 小时 2400 多条降到个位数,对得物技术补上团队级 AI 协作关键一环。

SmartCodeTech的博客 543

企业级 MultiAgent 的记忆系统:短期上下文与四层记忆架构实现|得物技术

在 MultiAgent 平台中,Agent 的"记忆"能力是实现智能对话和个性化服务的核心资产。本文深入剖析 Agent 记忆系统的设计理念与实现细节,重点解析长期记忆架构的写入与加载流程,涵盖 LLM 智能判断、语义检索、Token 预算控制、冲突处理等关键技术,为开发者提供完整的技术实现参考。

SmartCodeTech的博客 502

EP-Harness:从个人 AI Coding 到团队级 Agent 工作流|得物技术

AI Coding 个人用得爽,一到团队就崩。EP-Harness 把 Agent 从聊天工具变成团队协作成员——可管理、可追溯、可闭环。落地后高频异常从 2400+/4h 收敛到个位数。

SmartCodeTech的博客 694

得物知识问答:复合检索 Agent 的系统设计实践

从"搜到什么用什么"到"搜→筛→挖→验"自主决策闭环——我们造了一个有判断力的 RAG Agent,不是套壳。

SmartCodeTech的博客 734

实战从零开始构建一个Coding Agent:Violin |得物技术

理解了 coding agent 的构建原理,也就掌握了理解其他 agent 的一把钥匙。笔者对每天都在使用的 agent 原理很感兴趣,于是决定自己写一个:violin。

SmartCodeTech的博客 927

AI Native 交易核心系统的研发范式|得物技术

如何改造旧研发流程适配 AI 编码?本文提出五道标准化关口治理思路,依托 Claude Code Spec-Driven 插件打通需求澄清、方案设计、TDD 落地、门禁管控与埋点监控,构建带人工确认门控的完整工作流,以五层自底向上架构实现 AI 编码规范化落地。

SmartCodeTech的博客 975

推荐系统体验的数字化突破:得物自动化评测平台的技术实践|AICon 文章整理

「得物推荐 AI Harness 工程化实践系列」的末篇内容,本系列共三篇连载。本篇(末篇)详解得物推荐评测平台的完整技术体系:从主观体验量化到大模型自动化评测流水线,涵盖多维度指标设计、人机协作提示词校验闭环、分布式任务调度与成本精控等核心工程实现,以及单周百万级审计需求下实现 91% 资源成本优化的工业级落地实战细节。

SmartCodeTech的博客 1494

RAG 核心概念与原理:Chunking、Embedding、相似度、HNSW 与多路召回|得物技术

决定 RAG 效果的关键不在大模型,而是文本切块、查询改写、多路召回与精排。合理切块存好知识库内容,向量匹配抓语义、BM25 匹配关键词互补。先优化用户提问,快速召回一批相关文档,再用精排模型精细筛选,整套检索流程配合到位,问答准确度才会明显提升。

SmartCodeTech的博客 1079

从“机械应答“到“服务伙伴“:得物高可控智能客服的 Agent 工程实践|AICon 演讲整理

本次分享围绕以下核心技术展开:客服 Agent 挑战与架构设计(Single-Agent→Multi-Agent→Harness);高可控性数据飞轮(PE 自动化 + DPO 训练);RL 策略训练和人工经验对齐;多轮半双工消息流控制。

SmartCodeTech的博客 750

得物推荐系统诊断 Agent:从 “调接口” 到 “会思考”|AICon 演讲整理

本文是得物技术专家在 AICon 上海演讲整理的技术实录。AICon上海2026_全球人工智能开发与应用大会暨大模型应用生态展_InfoQ技术大会「得物推荐 AI Harness 工程化实践系列」的中篇内容,本系列共三篇连载。本篇(中篇)进一步详解得物推荐复杂业务场景下,AI代码从生成、防护校验到安全上线的完整技术体系、自研AI Harness整体架构框架、全流程安全防护机制、混合智能体核心算法实现,以及工业级工程落地的实战细节。

SmartCodeTech的博客 1364

得物 OceanBase 落地实践

得物选型OceanBase多模数据库应对业务挑战,通过验证其高可用架构、存储压缩技术及混合负载处理能力。测试显示OceanBase在复杂查询场景性能较MySQL提升130-200倍,在高并发TP/AP混合场景表现优异,存储成本降低40%+。通过DBA内部报表业务试点验证其稳定性后,逐步推广至核心业务场景,优化数据库技术栈,实现性能与成本的双重收益。

SmartCodeTech的博客 1383

AI UITester:AI Native 的 UI 自动化测试新范式|得物技术

ai_uitester 代表了 AI Native 的 UI 自动化测试新范式:这不仅是工具的升级,而是测试范式的转变 ------ 从 "代码驱动" 转向 "视觉驱动",从 "人工调试" 转向 "AI 自愈",从 "三端分离" 转向 "统一抽象"。

SmartCodeTech的博客 779

从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理

本文是得物技术专家在 AICon 上海演讲整理的技术实录。「得物推荐 AI Harness 工程化实践系列」的开篇内容,本系列共三篇连载。将系统拆解得物推荐复杂业务场景下,AI 代码从生成、防护校验到安全上线的完整技术体系,逐一详解自研 AI Harness 整体架构框架、全流程安全防护机制、混合智能体核心算法实现,以及工业级工程落地的实战细节。本篇(上篇):将整体介绍团队自研的 AI Harness 体系,包括建设思路、全生命周期防护机制、混合智能体架构及落地效果。

SmartCodeTech的博客 1082

从表单到 Agent:得物社区活动搭建的 AI 实践之路

一场营销活动从策划到上线,运营要在三个系统间跳转 10 + 次、填写 40 + 个字段。我们用 AI 重新设计了这条链路 —— 从 “AI 帮你填表单” 到 “两阶段 Agent + 聚合工作台”。这篇文章记录的不是技术细节,而是这条路上的选择和反思。

SmartCodeTech的博客 744

从埋点需求到规则资产:Hermes Agent 重构得物数仓工作流

埋点和指标需求中,消耗数据承接方的不是生成答案,而是补齐证据链、对齐历史口径、识别下游影响,并在生产写入前留下可追溯的确认记录。本文数据承接方指承接业务需求的数据同学或业务合作伙伴;后文讨论内部研发、元数据、查询和门禁能力在流程中的角色。

SmartCodeTech的博客 657

让 Claude Code 拥有自我进化和记忆系统|得物技术

本文记录了为 Claude Code 构建的一套持久化记忆与自我学习系统的设计思路与实现细节。这套系统让 AI 助手能够跨越会话边界记住用户习惯,并在每次对话结束后自动提炼行为规律和系统信息,通过向量检索快速提取关键信息,下一次对话时主动应用,逐步进化为更懂你的编程伙伴。

SmartCodeTech的博客 994

用 LLM Agent 重构告警排查流程|得物技术

告警排查需频繁切换日志、APM、链路追踪等多个平台,耗时 10~30 分钟,且高度依赖个人经验。我们做了 Troubleshooter——用 LLM Agent 自动完成数据采集、根因分析和处置建议生成。上线后中位数排查耗时从 20 分钟降到 4.4 分钟,覆盖 11 个服务和 10+ 种告警类型。

SmartCodeTech的博客 1008

HorizonVault 技术深潜:如何在 HDD 上做出 100GB/s+ 级大吞吐分布式存储|得物技术

HorizonVault是一款面向Kafka远程存储的高吞吐分布式存储引擎,通过分布式并行写入和状态感知调度解决冷数据存储的三大核心问题:吞吐瓶颈、性能抖动和恢复能力。系统采用分层架构,Meta负责全局资源调度,Broker处理请求路由,Store实现本地磁盘管理,形成完整的写入治理链路。通过将HDD磁盘提升为一等资源,实现顺序追加写入、多盘并行和慢盘隔离,在保证高吞吐的同时控制延迟。存储结构采用DiskStore组织磁盘资源,LogSegment顺序写入数据,IndexSegment定位读取,Change

SmartCodeTech的博客 892

Claude Code Harness 工程:数仓侧落地方案|得物技术

Harness 工程通过职责分层实现研发流水线可靠性提升。Claude 负责需求理解与代码生成等语义层工作;hooks 负责规范检查等确定性执行;Subagents 隔离血缘查询、自测等高 token 操作;Memory 承载跨会话状态持久化。四层协同使数仓 AI 开发从"对话式辅助"转变为"规则驱动的自动化流程"。

SmartCodeTech的博客 1101

BP Claw 破解 AI 编码输入难题 ——FlinkSpec 需求智能化实践|得物技术

本文为 FlinkSpec 系列之开篇,亦是这场工程化变革的序章。BP Claw 所立之处,不过链路之源。FlinkSpec 所图,乃以 AI 之力,将实时数仓从需求落地至验收上线的全程工序,熔铸为一套精密自洽、生生不息的智能工程体系。宏图未竟,后续系列将逐章揭幕,敬请期待!

SmartCodeTech的博客 1039
上一篇: 得物App白屏优化系列|归因篇
下一篇: 说说唯一ID与CAS|得物技术
得物技术
得物技术 得物技术官方账号 得物技术官方账号
博客等级 码龄6年 2492粉丝 408原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值