# 编译器假设
默认情况下,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-umd
和transform-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.exports
or迭代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)
使用检查js
or的运算符时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); }}