# 编译器假设

默认情况下,Babel 会尝试编译您的代码,以便它尽可能匹配本地行为。然而,这有时意味着生成更多的输出代码,或者更慢的输出代码,只是为了支持一些你不关心的边缘情况。

从 Babel 7.13.0 开始,你可以assumptions在你的配置中指定一个选项来告诉 Babel 它可以对你的代码做出哪些假设,以更好地优化编译结果。注意:这取代了插件中的各种loose选项,取而代之的是可以应用于多个插件的顶级选项(RFC 链接 (opens new window) )。

例如:

babel.config.json

{
  "targets": ">0.5%",
  "assumptions": {
    "noDocumentAll": true,
    "noClassCalls": true
  },
  "presets": ["@babel/preset-env"]
}

⚠ 这是高级功能。启用假设时请小心,因为它们不符合规范,可能会以意想不到的方式破坏您的代码。

# arrayLikeIsIterable (opens new window)

在传播或迭代类似数组的对象时,假设它实现了一个与[Symbol.iterator]native 具有相同行为的方法Array.prototype[Symbol.iterator],因此直接按索引迭代其元素。

例如,这对于在旧浏览器中迭代 DOM 集合很有用。

JavaScript

let images = $("img");for (const img of images) {  console.log(img);}const copy = [...images];

# constantReexports (opens new window)

从模块重新导出绑定时,假设它没有改变,因此直接导出它是安全的,就好像你在做

JavaScript

import { value as val } from "dep";

export const value = val;

注意:这也会影响transform-modules-umdtransform-modules-amd插件。

JavaScript

export { value } from "dependency";

# constantSuper (opens new window)

一个类的超类可以通过 using 随时改变Object.setPrototypeOf,使得 Babel 不可能静态地知道它。启用此选项后,Babel 假定它从未更改,因此它始终是放置在extends类声明中的子句中的值。

JavaScript

class Child extends Base {  method() {    super.method(2);  }}

# enumerableModuleMeta (opens new window)

在将 ESM 编译为 CJS 时,Babel在对象__esModule上定义了一个属性module.exports。假设您从不使用module.exportsor迭代or的键,因此定义为可枚举是安全的。require("your-module")``for..in``Object.keys``__esModule

JavaScript

export const number = 2;

# ignoreFunctionLength (opens new window)

函数有一个.length属性,它反映参数的数量直到最后一个非默认参数。启用此选项后,假设编译后的代码不依赖于此.length属性。

JavaScript

function fn(a, b = 2, c, d = 3) {  return a + b + c + d;}

# ignoreToPrimitiveHint (opens new window)

当使用可能调用[Symbol.toPrimitive] (opens new window) 对象方法的语言特性时,假设它们不会根据hint参数改变它们的行为。

JavaScript

let str = `a${foo}b`;

# iterableIsArray (opens new window)

当使用可迭代对象时(在数组解构、for-of 或 spreads 中),假设它是一个数组。

JavaScript

const [first, ...rest] = obj;call(first, ...obj);let arr = [first, ...obj];for (const el of obj) {  console.log(el);}

# mutableTemplateObject (opens new window)

不要用于Object.freeze为标记的模板文字创建的模板对象。这实际上意味着使用taggedTemplateLiteralLoose助手而不是taggedTemplateLiteral.

JavaScript

let str = tag`a`;

# noClassCalls (opens new window)

当转换类时,假设它们总是被实例化new并且它们永远不会被调用为函数。

JavaScript

class Test {  constructor() {    this.x = 2;  }}

# noDocumentAll (opens new window)

使用检查jsor的运算符时undefined,假设它们从未与特殊值一起使用document.all

JavaScript

let score = points ?? 0;let name = user?.name;

# noIncompleteNsImportDetection (opens new window)

假设在初始化之前没有观察到模块导出对象的自身属性。例如,当尝试访问 时ns.foo,它将undefined在打开或关闭此假设的情况下返回。区别在于when Object.prototype.hasOwnProperty.call(ns, "foo")会返回。false``noIncompleteNsImportDetection: true

JavaScript

export var foo;

# noNewArrows (opens new window)

假设代码从不尝试使用 实例化箭头函数new,根据规范这是不允许的。

注意:此假设默认为true. 它将默认false从 Babel 8 开始。

JavaScript

let getSum = (a, b) => {  return { sum: a + b }};

# objectRestNoSymbols (opens new window)

在对象解构中使用剩余模式时,假设解构的对象没有符号键,或者如果它们不被复制也不是问题。

JavaScript

let { name, ...attrs } = obj;

# privateFieldsAsProperties (opens new window)

假设“软隐私”对于私有字段就足够了,因此它们可以存储为具有唯一名称的公共不可枚举属性(而不是使用外部WeakMap)。这使得调试编译的私有字段更容易。

JavaScript

class Foo {  #method() {}  #field = 2;  run() {    this.#method();    this.#field++;  }}

⚠️ 使用内联 Babel 助手时,生成的字符串键在每个文件中都是唯一的,而不是全局的。当从具有相同名称的私有字段的不同字段扩展类时,这可能会导致冲突。

# privateFieldsAsSymbols (opens new window)

历史| | | | :--- | :--- | | | `` |

假设“软隐私”对于私有字段来说已经足够了,因此它们可以作为带有符号键的公共属性存储(而不是使用外部的WeakMap)。这使得调试编译的私有字段更容易。

class Foo {  #method() {}  #field = 2;  run() {    this.#method();    this.#field++;  }}

# pureGetters (opens new window)

假定吸气剂(如果存在)没有副作用并且可以多次访问。

JavaScript

let a = obj;a.b?.();

# setClassMethods (opens new window)

声明类时,假设方法不隐藏超类上的 getter,并且程序不依赖于不可枚举的方法。因此,分配方法而不是使用Object.defineProperty.

JavaScript

class Foo extends Bar {  method() {}  static check() {}}

# setComputedProperties (opens new window)

使用计算对象属性时,假设该对象不包含覆盖同一对象中定义的 setter 的属性,因此分配它们而不是使用定义它们是安全的Object.defineProperty

JavaScript

let obj = {  set name(value) {},  [key]: val}

# setPublicClassFields (opens new window)

当使用公共类字段时,假设它们不隐藏当前类、其子类或超类中的任何 getter。因此,分配它们而不是使用Object.defineProperty.

JavaScript

class Test {  field = 2;  static staticField = 3;}

# setSpreadProperties (opens new window)

使用对象传播时,假设传播的属性不会触发目标对象上的 getter,因此分配它们而不是使用定义它们是安全的Object.defineProperty

JavaScript

const result = {  set name(value) {},  ...obj,};

# skipForOfIteratorClosing (opens new window)

与迭代器一起使用时for-of,它应该始终关闭 with.return()和 with.throw()以防出现错误。当这个选项被调用时,Babel 假设这些方法没有定义或者是空的,并且它避免调用它们。

JavaScript

for (const val of iterable) {  console.log(val);}

# superIsCallableConstructor (opens new window)

扩展类时,假设超类是可调用的。这意味着不可能扩展原生类或内置类,而只能扩展编译类或 ES5function构造函数。

JavaScript

class Child extends Parent {  constructor() {    super(42);  }}
Last Updated: 6/7/2023, 9:06:23 AM