Start · Sprachen · JavaScript · Referenz · handler.preventExtensions()

handler.preventExtensions()

Methode

Trap für die interne Methode <code>[[PreventExtensions]]</code> – fängt <code>Object.preventExtensions()</code>, <code>Reflect.preventExtensions()</code>, <code>Object.seal()</code> und <code>Object.freeze()</code> auf einem Proxy ab.

seit JavaScript ES2015 Kategorie: method-property

Signatur

new Proxy(target, { preventExtensions(target) { … } })

Beschreibung

Die Methode preventExtensions() eines Proxy-Handlers wird immer dann aufgerufen, wenn ein Proxy nicht mehr erweiterbar gemacht werden soll. Mit ihr kannst du diesen Vorgang protokollieren, an Bedingungen knüpfen oder ganz verbieten, zum Beispiel wenn ein Objekt immer erweiterbar bleiben soll.

Ausgelöst wird der Trap durch Object.preventExtensions(proxy), Reflect.preventExtensions(proxy) sowie intern durch Object.seal(proxy) und Object.freeze(proxy).

Der Trap muss einen booleschen Wert liefern: true bedeutet, dass der Vorgang geklappt hat, false bedeutet, dass er gescheitert ist. Bei false wirft Object.preventExtensions() einen TypeError, während Reflect.preventExtensions() einfach false zurückgibt. Nicht-boolesche Rückgabewerte werden in einen Wahrheitswert umgewandelt.

Wichtig ist eine Invariante: Der Trap darf nur dann true zurückgeben, wenn das Zielobjekt danach tatsächlich nicht mehr erweiterbar ist, also Object.isExtensible(target) den Wert false ergibt. Sonst wirft die Engine einen TypeError. Am einfachsten hältst du diese Regel ein, indem du die Arbeit mit Reflect.preventExtensions(target) an das Zielobjekt weitergibst.

Parameter

Name Typ Default Beschreibung
$target Pflicht Object Das Zielobjekt des Proxys. Innerhalb des Traps ist this an das Handler-Objekt gebunden.

Rückgabewert

Typ
boolean
Beschreibung
true, wenn das Zielobjekt jetzt nicht mehr erweiterbar ist, sonst false. Andere Werte werden in einen Wahrheitswert umgewandelt.

Beispiele

Aufrufe protokollieren und an das Ziel weitergeben

const target = { name: 'Config' };

const proxy = new Proxy(target, {
  preventExtensions(t) {
    console.log('preventExtensions aufgerufen');
    return Reflect.preventExtensions(t);
  }
});

Object.preventExtensions(proxy);
console.log(Object.isExtensible(proxy));
console.log(Object.isExtensible(target));
preventExtensions aufgerufen false false

Sperren verbieten – Objekt bleibt erweiterbar

const registry = new Proxy({}, {
  preventExtensions() {
    return false; // Vorgang ablehnen
  }
});

console.log(Reflect.preventExtensions(registry));

try {
  Object.preventExtensions(registry);
} catch (err) {
  console.log(err instanceof TypeError);
}

registry.neu = 1; // funktioniert weiterhin
console.log(registry.neu);
false true 1

Verstoß gegen die Invariante

const proxy = new Proxy({}, {
  preventExtensions() {
    return true; // gelogen: Ziel bleibt erweiterbar
  }
});

try {
  Object.preventExtensions(proxy);
} catch (err) {
  console.log(err.name);
}
TypeError

Auch Object.freeze() löst den Trap aus

const proxy = new Proxy({ a: 1 }, {
  preventExtensions(t) {
    console.log('Trap ausgelöst');
    return Reflect.preventExtensions(t);
  }
});

Object.freeze(proxy);
console.log(Object.isFrozen(proxy));
Trap ausgelöst true

// Wichtig · Fallstricke

  • Invariante: Gibt der Trap true zurück, obwohl Object.isExtensible(target) noch true ergibt, wirft die Engine einen TypeError.
  • Object.preventExtensions() wirft bei false einen TypeError, Reflect.preventExtensions() gibt dagegen nur false zurück. Für Code, der mit Fehlschlägen rechnet, ist Reflect daher die bessere Wahl.
  • Object.seal() und Object.freeze() lösen den Trap ebenfalls aus. Wenn er false liefert, schlagen diese Aufrufe mit einem TypeError fehl.
  • Fehlt der Trap, wird die Operation unverändert an das Zielobjekt weitergegeben.
  • Der Trap sollte zum Trap isExtensible passen. Beide müssen den tatsächlichen Zustand des Zielobjekts widerspiegeln.
  • Kompatibilität: ES2015, in allen modernen Browsern und in Node.js verfügbar. Nicht nachrüstbar (kein Polyfill möglich).