Vai al contenuto principale

Assunzioni del compilatore

Traduzione Beta Non Ufficiale

Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →

Per impostazione predefinita, Babel cerca di compilare il tuo codice per replicare il più fedelmente possibile il comportamento nativo. Tuttavia, ciò può comportare la generazione di codice più voluminoso o meno performante, solo per supportare casi limite che potrebbero non interessarti.

A partire da Babel 7.13.0, puoi specificare un'opzione assumptions nella configurazione per indicare a Babel quali assunzioni può fare sul tuo codice, ottimizzando così il risultato della compilazione. Nota: questa funzionalità sostituisce le varie opzioni loose dei plugin con opzioni di alto livello applicabili a più plugin (link RFC).

Ad esempio:

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

Questa è una funzionalità avanzata. Presta attenzione quando abiliti le assunzioni, poiché non sono conformi alle specifiche e potrebbero causare comportamenti imprevisti nel tuo codice.

consiglio

Stai migrando dalle opzioni loose e spec di @babel/preset-env verso assunzioni granulari? Consulta "Migrazione dalle modalità "loose" e "spec" di @babel/preset-env" per la configurazione equivalente basata su assunzioni, pronta per essere copiata e incollata come punto di partenza.

arrayLikeIsIterable

Quando si effettua lo spread o l'iterazione di un oggetto array-like, si assume che implementi un metodo [Symbol.iterator] con lo stesso comportamento di Array.prototype[Symbol.iterator] nativo, iterando così direttamente i suoi elementi per indice.

Questo può essere utile, ad esempio, per iterare collezioni DOM in browser obsoleti.

JavaScript
let images = $("img");

for (const img of images) {
console.log(img);
}

const copy = [...images];

constantReexports

Quando si riesporta un binding da un modulo, si assume che non cambi e sia quindi sicuro esportarlo direttamente, come se si stesse facendo:

JavaScript
import { value as val } from "dep";

export const value = val;

NOTA: Ciò influisce anche sui plugin transform-modules-umd e transform-modules-amd.

JavaScript
export { value } from "dependency";

constantSuper

La superclasse di una classe può essere modificata in qualsiasi momento tramite Object.setPrototypeOf, rendendo impossibile per Babel conoscerla staticamente. Con questa opzione attiva, Babel assume che non venga mai modificata e corrisponda quindi sempre al valore specificato nella clausola extends nella dichiarazione della classe.

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

enumerableModuleMeta

Durante la compilazione da ESM a CJS, Babel definisce una proprietà __esModule sull'oggetto module.exports. Si assume che non si iteri mai sulle chiavi di module.exports o di require("your-module") usando for..in o Object.keys, rendendo quindi sicuro definire __esModule come enumerabile.

JavaScript
export const number = 2;

ignoreFunctionLength

Le funzioni possiedono una proprietà .length che riflette il numero di parametri fino all'ultimo parametro non predefinito. Con questa opzione attiva, si assume che il codice compilato non dipenda da questa proprietà .length.

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

ignoreToPrimitiveHint

Quando si utilizzano funzionalità linguistiche che potrebbero richiamare il metodo [Symbol.toPrimitive] degli oggetti, si assume che non modifichino il loro comportamento in base al parametro hint.

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

iterableIsArray

Quando si utilizza un oggetto iterabile (nella destrutturazione di array, cicli for-of o spread), si assume che sia un array.

JavaScript
const [first, ...rest] = obj;

call(first, ...obj);
let arr = [first, ...obj];

for (const el of obj) {
console.log(el);
}

mutableTemplateObject

Non utilizzare Object.freeze per l'oggetto template creato per i tagged template literal. Ciò significa sostanzialmente usare l'helper taggedTemplateLiteralLoose invece di taggedTemplateLiteral.

JavaScript
let str = tag`a`;

noClassCalls

Durante la trasformazione delle classi, si assume che vengano sempre istanziate con new e mai chiamate come funzioni.

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

noDocumentAll

Quando si utilizzano operatori che verificano la presenza di null o undefined, si assume che non vengano mai usati con il valore speciale document.all.

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

noIncompleteNsImportDetection

Si assume che nessuna proprietà propria di un oggetto di esportazione di un modulo venga osservata prima dell'inizializzazione. Ad esempio, quando si tenta di accedere a ns.foo, restituirà undefined sia con questa assunzione attiva che disattivata. La differenza è che Object.prototype.hasOwnProperty.call(ns, "foo") restituirebbe false quando noIncompleteNsImportDetection: true.

JavaScript
export var foo;

noNewArrows

Si assume che il codice non tenti mai di istanziare funzioni freccia utilizzando new, operazione non consentita secondo le specifiche.

NOTA: Questa assunzione è impostata di default a true. Verrà impostata di default a false a partire da Babel 8.

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

noUninitializedPrivateFieldAccess

History
VersionChanges
v7.24.0Added noUninitializedPrivateFieldAccess assumption

Si assume che il codice non tenti mai di accedere ai campi privati delle classi prima che vengano inizializzati. Ad esempio:

JavaScript
class Foo {
x = this.#y; // #y is not initialized yet
#y = 2;
}
JavaScript
class MyClass {
static #id = 123;

method() {
return MyClass.#id;
}
}

objectRestNoSymbols

Quando si utilizzano pattern rest nella destrutturazione di oggetti, si assume che gli oggetti destrutturati non abbiano chiavi di tipo symbol o che non sia un problema se non vengono copiate.

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

privateFieldsAsProperties

Si assume che una "soft privacy" sia sufficiente per i campi privati, e quindi che possano essere memorizzati come proprietà pubbliche non enumerabili con un nome univoco (invece di utilizzare un WeakMap esterno). Ciò rende più semplice il debug dei campi privati compilati.

JavaScript
class Foo {
#method() {}

#field = 2;

run() {
this.#method();
this.#field++;
}
}

Quando si utilizzano helper Babel inline, le chiavi stringa generate sono univoche per file e non globali. Ciò potrebbe causare conflitti quando si estendono classi da file diversi con campi privati con lo stesso nome.

privateFieldsAsSymbols

History
VersionChanges
v7.21.0Added privateFieldsAsSymbols assumption

Si assume che una "soft privacy" sia sufficiente per i campi privati, e quindi che possano essere memorizzati come proprietà pubbliche con una chiave di tipo symbol (invece di utilizzare un WeakMap esterno). Ciò rende più semplice il debug dei campi privati compilati.

class Foo {
#method() {}

#field = 2;

run() {
this.#method();
this.#field++;
}
}

pureGetters

Si assume che i getter, se presenti, non abbiano effetti collaterali e possano essere accessibili più volte.

JavaScript
let a = obj;

a.b?.();

setClassMethods

Quando si dichiarano classi, si assume che i metodi non oscurino gli accessor o le proprietà non scrivibili sul prototipo della superclasse, e che il programma non dipenda dal fatto che i metodi siano non enumerabili. Pertanto, è sicuro assegnare i metodi invece di utilizzare Object.defineProperty.

JavaScript
class Foo extends Bar {
method() {}

static check() {}
}

setComputedProperties

Quando si utilizzano proprietà calcolate di oggetti, si assume che l'oggetto non contenga proprietà che sovrascrivono setter definiti nello stesso oggetto, e quindi è sicuro assegnarle invece di definirle utilizzando Object.defineProperty.

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

setPublicClassFields

Quando si utilizzano campi pubblici di classe, si assume che non oscurino alcun getter nella classe corrente, nelle sue sottoclassi o nella sua superclasse. Pertanto, è sicuro assegnarli invece di utilizzare Object.defineProperty.

JavaScript
class Test {
field = 2;

static staticField = 3;
}

setSpreadProperties

Quando si utilizza lo spread di oggetti, si assume che le proprietà spreadate non attivino i getter sull'oggetto di destinazione e quindi è sicuro assegnarle invece di definirle utilizzando Object.defineProperty.

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

skipForOfIteratorClosing

Quando si utilizza for-of con un iteratore, questo dovrebbe sempre essere chiuso con .return() e con .throw() in caso di errore. Quando questa opzione è attiva, Babel assume che tali metodi non siano definiti o siano vuoti, ed evita di chiamarli.

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

superIsCallableConstructor

Quando si estendono classi, si assume che la superclasse sia chiamabile. Ciò significa che non sarà possibile estendere classi native o built-in, ma solo classi compilate o costruttori ES5 di tipo function.

JavaScript
class Child extends Parent {
constructor() {
super(42);
}
}

Migrazione dalle modalità "loose" e "spec" di @babel/preset-env

L'opzione loose di @babel/preset-env equivale alla seguente configurazione:

JSON
{
"presets": [
["@babel/preset-env", { "exclude": ["transform-typeof-symbol"] }]
],
"assumptions": {
"arrayLikeIsIterable": true,
"constantReexports": true,
"ignoreFunctionLength": true,
"ignoreToPrimitiveHint": true,
"mutableTemplateObject": true,
"noClassCalls": true,
"noDocumentAll": true,
"objectRestNoSymbols": true,
"privateFieldsAsProperties": true,
"pureGetters": true,
"setClassMethods": true,
"setComputedProperties": true,
"setPublicClassFields": true,
"setSpreadProperties": true,
"skipForOfIteratorClosing": true,
"superIsCallableConstructor": true
}
}

L'opzione spec di @babel/preset-env equivale alla seguente configurazione:

JSON
{
"presets": ["@babel/preset-env"],
"assumptions": {
"noNewArrows": false,
}
}