Signatur
Beschreibung
Die Methode handler.set() wird im Handler-Objekt eines Proxy definiert. Sie wird immer dann aufgerufen, wenn einer Eigenschaft des Proxys ein Wert zugewiesen wird. Das gilt für die Punkt- und Klammerschreibweise (proxy.foo = v, proxy[key] = v), für Reflect.set() und auch für Zuweisungen an Objekte, die den Proxy in ihrer Prototypenkette haben.
Typische Einsatzzwecke sind Validierung (Typen oder Wertebereiche prüfen), Reaktivität (bei Änderungen Beobachter benachrichtigen, so wie es Vue 3 macht), Protokollierung, schreibgeschützte Sichten auf Objekte und berechnete bzw. normalisierte Werte.
Die Falle muss einen booleschen Wert zurückgeben. true steht für eine erfolgreiche Zuweisung. Bei false wirft die Zuweisung im Strict Mode (also auch in ES-Modulen und Klassen) einen TypeError, außerhalb des Strict Mode scheitert sie still. Wer das Standardverhalten beibehalten will, sollte am Ende Reflect.set(target, property, value, receiver) aufrufen und dessen Ergebnis zurückgeben. So funktionieren Setter und Vererbung weiterhin richtig.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $target Pflicht | object | Das ursprüngliche Zielobjekt des Proxys. | |
| $property Pflicht | string | symbol | Name bzw. Schlüssel der Eigenschaft, die gesetzt wird. Numerische Indizes kommen als String an, zum Beispiel "0". |
|
| $value Pflicht | any | Der neue Wert, der zugewiesen werden soll. | |
| $receiver Pflicht | object | Das Objekt, an das die Zuweisung ursprünglich gerichtet war. Meist ist das der Proxy selbst, es kann aber auch ein Objekt sein, das den Proxy als Prototyp erbt. Wird als this für Setter verwendet. |
Rückgabewert
true, wenn die Zuweisung erfolgreich war, sonst false. Bei false wird im Strict Mode ein TypeError geworfen. Andere Rückgabewerte werden in einen booleschen Wert umgewandelt.Beispiele
Validierung von Eigenschaftswerten
const person = new Proxy({}, {
set(target, prop, value, receiver) {
if (prop === 'alter') {
if (!Number.isInteger(value) || value < 0) {
throw new TypeError(`Ungültiges Alter: ${value}`);
}
}
return Reflect.set(target, prop, value, receiver);
}
});
person.alter = 42;
console.log(person.alter);
try {
person.alter = -5;
} catch (err) {
console.log(err.message);
}
Reaktives Objekt mit Änderungs-Callback
const reactive = (obj, onChange) => new Proxy(obj, {
set(target, prop, value, receiver) {
const alt = target[prop];
const ok = Reflect.set(target, prop, value, receiver);
if (ok && alt !== value) onChange(prop, alt, value);
return ok;
}
});
const state = reactive({ count: 0 }, (prop, alt, neu) => {
console.log(`${String(prop)}: ${alt} -> ${neu}`);
});
state.count++;
state.count = 1; // gleicher Wert, kein Callback
state.count += 5;
Schreibschutz mit false-Rückgabe im Strict Mode
'use strict';
const config = new Proxy({ apiUrl: 'https://api.example.com' }, {
set() {
return false; // Zuweisung verweigern
}
});
try {
config.apiUrl = 'http://evil.example';
} catch (err) {
console.log(err instanceof TypeError);
}
console.log(config.apiUrl);
Array-Indizes kommen als String an
const log = [];
const arr = new Proxy([], {
set(target, prop, value, receiver) {
log.push(`${typeof prop}:${String(prop)}`);
return Reflect.set(target, prop, value, receiver);
}
});
arr.push('a');
console.log(log);
// Wichtig · Fallstricke
- Invarianten: Ist die Eigenschaft auf dem Ziel eine nicht beschreibbare, nicht konfigurierbare Dateneigenschaft, darf der Wert nicht geändert werden. Ist sie eine nicht konfigurierbare Accessor-Eigenschaft ohne Setter (
set: undefined), darf die Zuweisung nicht als erfolgreich gemeldet werden. In beiden Fällen führt die Rückgabe vontruezu einemTypeError. - Strict Mode: Eine
false-Rückgabe führt nur im Strict Mode zu einemTypeError. In ES-Modulen und Klassenkörpern ist der Strict Mode automatisch aktiv. receiverweitergeben:target[prop] = valuestattReflect.set(…, receiver)umgeht Setter mit korrektemthisund stört die Vererbung über Prototypen.- Nicht abgefangen werden
Object.defineProperty()(dafür gibt es die FalledefineProperty) und Änderungen an verschachtelten Objekten (proxy.a.b = 1ruft auf dem äußeren Proxy nurgetauf). Für tiefe Reaktivität müssen verschachtelte Objekte ebenfalls in Proxys verpackt werden. - Leistung: Proxy-Fallen sind deutlich langsamer als direkte Zuweisungen. In sehr heißen Schleifen solltest du sie vermeiden.
- Kompatibilität: Wird von allen modernen Browsern und von Node.js 6+ unterstützt. Proxy lässt sich nicht per Polyfill nachbilden, der Internet Explorer wird also nicht unterstützt.