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

handler.ownKeys()

Methode

Trap für die interne Methode <code>[[OwnPropertyKeys]]</code> – fängt <code>Object.keys()</code>, <code>Reflect.ownKeys()</code>, <code>for...in</code> und ähnliche Operationen auf einem Proxy ab.

seit JavaScript ES2015 Kategorie: method-property

Signatur

handler.ownKeys(target)

Beschreibung

Die Methode ownKeys() im Handler-Objekt eines Proxy wird immer dann aufgerufen, wenn die eigenen Eigenschaftsschlüssel des Proxys abgefragt werden. Dazu gehören Object.getOwnPropertyNames(), Object.getOwnPropertySymbols(), Object.keys(), Object.entries(), Object.values(), Reflect.ownKeys(), for...in, Object.assign() und der Spread-Operator { ...obj }.

Typische Einsatzfälle sind das Verbergen interner oder „privater“ Eigenschaften (z. B. alles mit Präfix _), das Filtern oder Umsortieren von Schlüsseln und das Anbieten virtueller Eigenschaften, die gar nicht auf dem Zielobjekt liegen.

Der Trap muss ein array-ähnliches Objekt zurückgeben, dessen Elemente ausschließlich Strings oder Symbole sind, ohne Duplikate. Operationen wie Object.keys() filtern das Ergebnis anschließend noch: Es werden nur Schlüssel berücksichtigt, für die getOwnPropertyDescriptor einen aufzählbaren Deskriptor liefert. Wer virtuelle Schlüssel in Object.keys() sehen will, muss daher zusätzlich den Trap getOwnPropertyDescriptor implementieren.

Parameter

Name Typ Default Beschreibung
$target Pflicht object Das Zielobjekt, das dem Proxy-Konstruktor übergeben wurde.

Rückgabewert

Typ
Array<string | symbol>
Beschreibung
Eine Liste (array-ähnliches Objekt) der eigenen Eigenschaftsschlüssel. Jedes Element muss ein string oder symbol sein; Duplikate sind nicht erlaubt.

Beispiele

Private Eigenschaften mit Unterstrich verbergen

const user = { name: 'Anna', role: 'admin', _passwordHash: 'x9f3...' };

const safeUser = new Proxy(user, {
  ownKeys(target) {
    return Reflect.ownKeys(target).filter(
      (key) => typeof key !== 'string' || !key.startsWith('_')
    );
  }
});

console.log(Object.keys(safeUser));
console.log(JSON.stringify(safeUser));
console.log({ ...safeUser });
[ 'name', 'role' ] {"name":"Anna","role":"admin"} { name: 'Anna', role: 'admin' }

Welche Operationen den Trap auslösen

const sym = Symbol('id');
const obj = { a: 1, [sym]: 42 };

const logged = new Proxy(obj, {
  ownKeys(target) {
    console.log('ownKeys aufgerufen');
    return Reflect.ownKeys(target);
  }
});

console.log(Object.getOwnPropertyNames(logged));
console.log(Object.getOwnPropertySymbols(logged));
for (const key in logged) console.log('for...in:', key);
ownKeys aufgerufen [ 'a' ] ownKeys aufgerufen [ Symbol(id) ] ownKeys aufgerufen for...in: a

Virtuelle Schlüssel für Object.keys() sichtbar machen

const config = new Proxy({}, {
  ownKeys() {
    return ['host', 'port'];
  },
  getOwnPropertyDescriptor(target, key) {
    // Ohne diesen Trap filtert Object.keys() die virtuellen Schlüssel heraus
    return { value: key === 'host' ? 'localhost' : 8080, enumerable: true, configurable: true };
  },
  get(target, key) {
    return key === 'host' ? 'localhost' : key === 'port' ? 8080 : undefined;
  }
});

console.log(Object.keys(config));
console.log(Object.entries(config));
[ 'host', 'port' ] [ [ 'host', 'localhost' ], [ 'port', 8080 ] ]

// Wichtig · Fallstricke

Invarianten – bei Verletzung wirft die Engine einen TypeError:

  • Das Ergebnis muss ein Objekt sein; die Elemente müssen string oder symbol sein, und es darf keine Duplikate geben.
  • Alle nicht konfigurierbaren eigenen Eigenschaften des Ziels müssen enthalten sein. Solche Schlüssel lassen sich also nicht verbergen.
  • Ist das Ziel nicht erweiterbar (Object.preventExtensions(), Object.seal(), Object.freeze()), muss die Liste genau die eigenen Schlüssel des Ziels enthalten – keine mehr und keine weniger.

Fallstricke: Gibt der Trap Schlüssel zurück, die es auf dem Ziel nicht gibt, erscheinen sie in Reflect.ownKeys(), werden von Object.keys() aber stillschweigend herausgefiltert, solange kein passender getOwnPropertyDescriptor-Trap existiert. ownKeys verbirgt Schlüssel nur bei der Aufzählung. Ein direkter Zugriff (proxy._secret) oder der in-Operator funktioniert weiterhin. Wer das verhindern will, braucht zusätzlich die Traps get und has.

Kompatibilität: Wird von allen modernen Browsern und von Node.js ab Version 6 unterstützt. Da sich Proxies nicht per Polyfill nachbilden lassen, funktionieren sie im Internet Explorer nicht.