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

handler.isExtensible()

Methode

Trap eines Proxy-Handlers, die die interne Methode <code>[[IsExtensible]]</code> abfängt, etwa bei <code>Object.isExtensible()</code> oder <code>Reflect.isExtensible()</code>.

seit JavaScript ES2015 Kategorie: method-property

Signatur

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

Beschreibung

Die Methode isExtensible() im Handler-Objekt eines Proxy wird aufgerufen, sobald jemand fragt, ob dem Proxy noch neue Eigenschaften hinzugefügt werden können. Das passiert bei Object.isExtensible(proxy), Reflect.isExtensible(proxy) und indirekt auch bei Object.isFrozen() und Object.isSealed().

Nützlich ist die Trap vor allem für Protokollierung, Debugging und Zugriffsüberwachung: Man sieht, wann und wie oft Code die Erweiterbarkeit eines Objekts prüft. Den Rückgabewert frei verändern kann man aber nicht. Die Sprachspezifikation schreibt eine strenge Invariante vor: Das Ergebnis muss mit Object.isExtensible(target) übereinstimmen.

In der Praxis leitet man daher fast immer an Reflect.isExtensible(target) weiter und ergänzt davor oder danach eigene Logik. Wer die Erweiterbarkeit wirklich ändern will, muss das Zielobjekt selbst anpassen, zum Beispiel mit Object.preventExtensions(target), oder zusätzlich die Trap preventExtensions nutzen.

Parameter

Name Typ Default Beschreibung
$target Pflicht object Das Zielobjekt des Proxys (das ursprüngliche Objekt, nicht der Proxy selbst).

Rückgabewert

Typ
boolean
Beschreibung
Gibt an, ob das Objekt erweiterbar ist. Andere Werte werden in einen booleschen Wert umgewandelt. Das Ergebnis muss gleich Object.isExtensible(target) sein, sonst wird ein TypeError ausgelöst.

Beispiele

Prüfungen der Erweiterbarkeit protokollieren

const config = { debug: true };

const proxy = new Proxy(config, {
  isExtensible(target) {
    console.log('Erweiterbarkeit wird geprüft');
    return Reflect.isExtensible(target);
  }
});

console.log(Object.isExtensible(proxy));
Object.preventExtensions(config);
console.log(Reflect.isExtensible(proxy));
Erweiterbarkeit wird geprüft true Erweiterbarkeit wird geprüft false

Invariante verletzt: TypeError

const proxy = new Proxy({}, {
  // Das Ziel ist erweiterbar, die Trap behauptet das Gegenteil
  isExtensible: () => false
});

try {
  Object.isExtensible(proxy);
} catch (err) {
  console.log(err instanceof TypeError, err.message);
}
true 'isExtensible' on proxy: trap result does not reflect extensibility of proxy target (which is 'true')

Zugriffe zählen, zum Beispiel für Tests

const createCountingProxy = (obj) => {
  const stats = { isExtensibleCalls: 0 };
  const proxy = new Proxy(obj, {
    isExtensible(target) {
      stats.isExtensibleCalls++;
      return Reflect.isExtensible(target);
    }
  });
  return { proxy, stats };
};

const { proxy, stats } = createCountingProxy({ a: 1 });
Object.isExtensible(proxy);
Object.isFrozen(proxy); // löst die Trap ebenfalls aus
console.log(stats.isExtensibleCalls);
2

// Wichtig · Fallstricke

  • Invariante: Object.isExtensible(proxy) muss immer denselben Wert liefern wie Object.isExtensible(target). Bei einer Abweichung wird ein TypeError ausgelöst. Die Trap kann das Ergebnis also nicht vortäuschen.
  • Fehlt die Trap, wird die Operation direkt an das Zielobjekt weitergereicht.
  • Object.isFrozen() und Object.isSealed() rufen die Trap ebenfalls auf. Das kann in Zählern oder Protokollen zu unerwarteten zusätzlichen Aufrufen führen.
  • Innerhalb der Trap bezeichnet this das Handler-Objekt, nicht den Proxy.
  • Der genaue Wortlaut der Fehlermeldung hängt von der JavaScript-Engine ab. Die Ausgabe im Beispiel stammt aus V8 (Chrome, Node.js).
  • Wird von allen modernen Browsern und von Node.js ab Version 6 unterstützt. Der Internet Explorer unterstützt die Trap nicht, und sie lässt sich auch nicht durch ein Polyfill nachrüsten.