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

handler.has()

Methode

Die Proxy-Falle <code>has()</code> fängt die interne Methode [[HasProperty]] ab, also z. B. den <code>in</code>-Operator und Zugriffe innerhalb von <code>with</code>.

seit JavaScript ES2015 Kategorie: method-property

Signatur

new Proxy(target, { has(target, property) { … } })

Beschreibung

Die Methode handler.has() ist eine Falle (Trap) im Handler-Objekt eines Proxy. Sie wird immer dann aufgerufen, wenn die Engine prüft, ob eine Eigenschaft auf dem Proxy oder in seiner Prototypenkette existiert. Damit legst du selbst fest, welche Schlüssel für den in-Operator „sichtbar“ sind.

Ausgelöst wird die Falle durch:

  • den Operator property in proxy
  • property in Object.create(proxy), also wenn der Proxy in der Prototypenkette eines anderen Objekts liegt
  • Reflect.has(proxy, property)
  • die Namensauflösung in with(proxy) { … } (nur im nicht-strikten Modus)

Typische Einsatzzwecke sind das Verstecken interner bzw. „privater“ Eigenschaften (etwa mit Präfix _), Bereichsprüfungen wie 5 in range oder virtuelle Objekte, deren Schlüssel dynamisch berechnet werden. Wichtig: has() betrifft nicht Object.hasOwn(), hasOwnProperty(), for...in oder Object.keys(). Dafür gibt es eigene Fallen wie getOwnPropertyDescriptor und ownKeys.

Parameter

Name Typ Default Beschreibung
$target Pflicht object Das Zielobjekt, das der Proxy umhüllt.
$property Pflicht string | symbol Der geprüfte Schlüssel. Zahlen werden vorher in Strings umgewandelt (1 in p liefert "1").

Rückgabewert

Typ
boolean
Beschreibung
Gibt an, ob die Eigenschaft als vorhanden gilt. Jeder andere Wert wird in einen Wahrheitswert umgewandelt (ToBoolean).

Beispiele

Private Eigenschaften vor dem in-Operator verstecken

const user = { name: 'Ada', _passwordHash: 'x9f…' };

const safeUser = new Proxy(user, {
  has(target, prop) {
    if (typeof prop === 'string' && prop.startsWith('_')) return false;
    return Reflect.has(target, prop);
  }
});

console.log('name' in safeUser);
console.log('_passwordHash' in safeUser);
console.log('toString' in safeUser); // aus der Prototypenkette
true false true

Zahlenbereich mit in prüfen

const range = (min, max) => new Proxy({}, {
  has(_target, prop) {
    const n = Number(prop);
    return Number.isFinite(n) && n >= min && n <= max;
  }
});

const workingHours = range(8, 17);
const hour = new Date(2024, 0, 1, 10).getHours();

console.log(hour in workingHours);
console.log(20 in workingHours);
true false

Invariante verletzen – TypeError

const target = {};
Object.defineProperty(target, 'id', { value: 1, configurable: false });

const p = new Proxy(target, { has: () => false });

try {
  console.log('id' in p);
} catch (err) {
  console.log(err instanceof TypeError);
}
true

Aufruf über Reflect.has und Prototypenkette

const logged = new Proxy({ a: 1 }, {
  has(target, prop) {
    console.log(`has: ${String(prop)}`);
    return Reflect.has(target, prop);
  }
});

Reflect.has(logged, 'a');
const child = Object.create(logged);
console.log('b' in child);
has: a has: b false

// Wichtig · Fallstricke

Invarianten: Die Engine wirft einen TypeError, wenn die Falle false liefert, obwohl

  • die Eigenschaft als eigene, nicht konfigurierbare Eigenschaft auf dem Ziel existiert, oder
  • die Eigenschaft als eigene Eigenschaft existiert und das Ziel nicht erweiterbar ist (Object.preventExtensions, seal, freeze).

Kein echter Schutz: Mit has versteckte Eigenschaften lassen sich weiterhin über get, Object.keys(), hasOwnProperty() oder for...in finden. Für Konsistenz solltest du auch get, ownKeys und getOwnPropertyDescriptor abfangen. Für echte Kapselung nimm private Klassenfelder (#feld).

Symbole: property kann ein Symbol sein. Deshalb vor String-Methoden wie startsWith den Typ prüfen, sonst entsteht ein TypeError.

Kompatibilität: Wird in allen modernen Browsern und in Node.js ab Version 6 unterstützt. Lässt sich nicht polyfillen und fehlt im Internet Explorer.