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

handler.set()

Methode

Falle für die interne Methode <code>[[Set]]</code>: fängt Schreibzugriffe wie <code>proxy.x = 1</code> oder <code>proxy["x"] = 1</code> auf einem Proxy ab.

seit JavaScript ES2015 Kategorie: method-property

Signatur

new Proxy(target, { set(target, property, value, receiver) { … } })

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

Typ
boolean
Beschreibung
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);
}
42 Ungültiges Alter: -5

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;
count: 0 -> 1 count: 1 -> 6

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);
true https://api.example.com

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);
[ 'string:0', 'string:length' ]

// 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 von true zu einem TypeError.
  • Strict Mode: Eine false-Rückgabe führt nur im Strict Mode zu einem TypeError. In ES-Modulen und Klassenkörpern ist der Strict Mode automatisch aktiv.
  • receiver weitergeben: target[prop] = value statt Reflect.set(…, receiver) umgeht Setter mit korrektem this und stört die Vererbung über Prototypen.
  • Nicht abgefangen werden Object.defineProperty() (dafür gibt es die Falle defineProperty) und Änderungen an verschachtelten Objekten (proxy.a.b = 1 ruft auf dem äußeren Proxy nur get auf). 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.