| [ Web Proxy ] |
| Viewing: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Proxy | [Back] [Original] |
Get to know MDN better
Dieser Inhalt wurde automatisch aus dem Englischen bersetzt, und kann Fehler enthalten. Erfahre mehr ber dieses Experiment.
Diese Funktion ist gut etabliert und funktioniert auf vielen Gerten und in vielen Browserversionen. Sie ist seit September 2016 browserbergreifend verfgbar.
Das Proxy-Objekt ermglicht Ihnen, einen Proxy fr ein anderes Objekt zu erstellen, der die grundlegenden Operationen fr dieses Objekt abfangen und neu definieren kann.
Das Proxy-Objekt ermglicht Ihnen, ein Objekt zu erstellen, das anstelle des Originalobjekts verwendet werden kann, aber grundlegende Object-Operationen wie das Lesen, Setzen und Definieren von Eigenschaften neu definieren kann. Proxy-Objekte werden hufig verwendet, um den Zugriff auf Eigenschaften zu protokollieren, Eingaben zu validieren, zu formatieren oder zu bereinigen und vieles mehr.
Sie erstellen einen Proxy mit zwei Parametern:
target: das Originalobjekt, das Sie proxyen mchtenhandler: ein Objekt, das definiert, welche Operationen abgefangen und wie die abgefangenen Operationen neu definiert werden sollenZum Beispiel erstellt dieser Code einen Proxy fr das target-Objekt.
const target = {
message1: "hello",
message2: "everyone",
};
const handler1 = {};
const proxy1 = new Proxy(target, handler1);
Da der Handler leer ist, verhlt sich dieser Proxy genauso wie das ursprngliche Ziel:
console.log(proxy1.message1); // hello
console.log(proxy1.message2); // everyone
Um den Proxy anzupassen, definieren wir Funktionen im Handler-Objekt:
const target = {
message1: "hello",
message2: "everyone",
};
const handler2 = {
get(target, prop, receiver) {
return "world";
},
};
const proxy2 = new Proxy(target, handler2);
Hier haben wir eine Implementierung des get() Handlers bereitgestellt, der Zugriffsversuche auf Eigenschaften im Ziel abfngt.
Handler-Funktionen werden manchmal als Traps bezeichnet, vermutlich weil sie Aufrufe an das Zielobjekt abfangen. Der Trap im obigen handler2 definiert alle Eigenschafts-Accessoren neu:
console.log(proxy2.message1); // world
console.log(proxy2.message2); // world
Proxys werden oft mit dem Reflect-Objekt verwendet, das einige Methoden mit denselben Namen wie die Proxy-Traps bereitstellt. Die Reflect-Methoden bieten die reflexiven Semantiken fr das Aufrufen der entsprechenden objektinternen Methoden. Zum Beispiel knnen wir Reflect.get aufrufen, wenn wir das Verhalten des Objekts nicht neu definieren mchten:
const target = {
message1: "hello",
message2: "everyone",
};
const handler3 = {
get(target, prop, receiver) {
if (prop === "message2") {
return "world";
}
return Reflect.get(...arguments);
},
};
const proxy3 = new Proxy(target, handler3);
console.log(proxy3.message1); // hello
console.log(proxy3.message2); // world
Die Reflect-Methode interagiert immer noch mit dem Objekt durch objektinterne Methoden sie deproxifiziert den Proxy nicht, wenn sie auf einem Proxy aufgerufen wird. Wenn Sie Reflect-Methoden innerhalb eines Proxy-Traps verwenden und der Reflect-Methodenaufruf erneut vom Trap abgefangen wird, kann es zu einer Endlosschleife kommen.
Die folgenden Begriffe werden verwendet, wenn ber die Funktionalitt von Proxys gesprochen wird.
Das Objekt, das als zweites Argument an den Proxy-Konstruktor bergeben wird. Es enthlt die Traps, die das Verhalten des Proxys definieren.
Die Funktion, die das Verhalten fr die entsprechende objektinterne Methode definiert. (Dies ist analog zum Konzept der Traps in Betriebssystemen.)
Objekt, das der Proxy virtualisiert. Es wird oft als Speicher-Backend fr den Proxy verwendet. Invarianten (Semantiken, die unverndert bleiben) in Bezug auf die Nichterweiterbarkeit des Objekts oder nicht konfigurierbare Eigenschaften werden gegen das Ziel berprft.
Semantiken, die unverndert bleiben, wenn benutzerdefinierte Operationen implementiert werden. Wenn Ihre Trap-Implementierung die Invarianten eines Handlers verletzt, wird ein TypeError ausgelst.
Objekte sind Sammlungen von Eigenschaften. Die Sprache bietet jedoch keine Mechanismen, um die im Objekt gespeicherten Daten direkt zu manipulieren stattdessen definiert das Objekt einige interne Methoden, die spezifizieren, wie mit ihm interagiert werden kann. Zum Beispiel, wenn Sie obj.x lesen, erwarten Sie vielleicht, dass Folgendes passiert:
x-Eigenschaft wird im Prototypen-Verkettung gesucht, bis sie gefunden wird.x eine Dateneigenschaft ist, wird das value-Attribut des Eigenschaftsdeskriptors zurckgegeben.x eine Accessor-Eigenschaft ist, wird der Getter aufgerufen und der Rckgabewert des Getters zurckgegeben.Es gibt nichts Besonderes an diesem Prozess in der Sprache es liegt daran, dass gewhnliche Objekte standardmig eine [[Get]]-interne Methode haben, die mit diesem Verhalten definiert ist. Die obj.x-Eigenschaftsabzugssyntax ruft einfach die [[Get]]-Methode des Objekts auf und das Objekt verwendet seine eigene interne Methodenumsetzung, um zu bestimmen, was zurckgegeben werden soll.
Ein anderes Beispiel: Arrays unterscheiden sich von normalen Objekten, da sie eine magische length-Eigenschaft haben, die, wenn modifiziert, automatisch leere Slots zuordnet oder Elemente aus dem Array entfernt. Ebenso ndert das Hinzufgen von Array-Elementen automatisch die length-Eigenschaft. Dies liegt daran, dass Arrays eine [[DefineOwnProperty]]-interne Methode haben, die wei, length zu aktualisieren, wenn ein ganzzahliger Index geschrieben wird, oder die Array-Inhalte zu aktualisieren, wenn length geschrieben wird. Solche Objekte, deren interne Methoden unterschiedliche Implementierungen als gewhnliche Objekte haben, werden als exotische Objekte bezeichnet. Proxy ermglicht es Entwicklern, ihre eigenen exotischen Objekte mit voller Kapazitt zu definieren.
Alle Objekte haben die folgenden internen Methoden:
| Interne Methode | Entsprechender Trap |
|---|---|
[[GetPrototypeOf]] |
getPrototypeOf() |
[[SetPrototypeOf]] |
setPrototypeOf() |
[[IsExtensible]] |
isExtensible() |
[[PreventExtensions]] |
preventExtensions() |
[[GetOwnProperty]] |
getOwnPropertyDescriptor() |
[[DefineOwnProperty]] |
defineProperty() |
[[HasProperty]] |
has() |
[[Get]] |
get() |
[[Set]] |
set() |
[[Delete]] |
deleteProperty() |
[[OwnPropertyKeys]] |
ownKeys() |
Funktionsobjekte haben auch die folgenden internen Methoden:
| Interne Methode | Entsprechender Trap |
|---|---|
[[Call]] |
apply() |
[[Construct]] |
construct() |
Es ist wichtig zu erkennen, dass alle Interaktionen mit einem Objekt letztendlich auf die Aufrufung einer dieser internen Methoden hinauslaufen und dass sie alle durch Proxys anpassbar sind. Das bedeutet, dass fast kein Verhalten (auer bestimmte kritische Invarianten) in der Sprache garantiert ist alles wird durch das Objekt selbst definiert. Wenn Sie delete obj.x ausfhren, gibt es keine Garantie dafr, dass "x" in obj danach false zurckgibt es hngt von den Implementierungen des Objekts von [[Delete]] und [[HasProperty]] ab. Ein delete obj.x kann Dinge in die Konsole protokollieren, einen globalen Status ndern oder sogar eine neue Eigenschaft definieren, anstatt die bestehende zu lschen, obwohl diese Semantiken in Ihrem eigenen Code vermieden werden sollten.
Alle internen Methoden werden von der Sprache selbst aufgerufen und sind in JavaScript-Code nicht direkt zugnglich. Der Reflect-Namensraum bietet Methoden, die wenig mehr tun, als die internen Methoden aufzurufen, auer einigen Eingabenormalisierungen und -validierungen. Auf jeder Trap-Seite listen wir mehrere typische Situationen auf, wann der Trap aufgerufen wird, aber diese internen Methoden werden an sehr vielen Stellen aufgerufen. Zum Beispiel lesen und schreiben Array-Methoden auf Array durch diese internen Methoden, sodass Methoden wie push() auch get()- und set()-Traps aufrufen wrden.
Die meisten internen Methoden sind in ihrem Zweck klar. Die einzigen beiden, die verwirrt werden knnten, sind [[Set]] und [[DefineOwnProperty]]. Fr normale Objekte ruft erstere Setter auf; letztere nicht. (Und [[Set]] ruft [[DefineOwnProperty]] intern auf, wenn keine bestehende Eigenschaft vorhanden ist oder die Eigenschaft eine Dateneigenschaft ist.) Whrend Sie vielleicht wissen, dass die obj.x = 1-Syntax [[Set]] verwendet und Object.defineProperty() [[DefineOwnProperty]] verwendet, ist es nicht sofort ersichtlich, welche Semantiken andere eingebaute Methoden und Syntaxen verwenden. Zum Beispiel verwenden Klassenfelder die [[DefineOwnProperty]]-Semantik, weshalb Setter, die in der Superklasse definiert sind, nicht aufgerufen werden, wenn ein Feld in der abgeleiteten Klasse deklariert wird.
Proxy()Erstellt ein neues Proxy-Objekt.
Hinweis:
Es gibt keine Proxy.prototype-Eigenschaft, daher haben Proxy-Instanzen keine speziellen Eigenschaften oder Methoden.
Proxy.revocable()Erstellt ein widerrufbares Proxy-Objekt.
In diesem Beispiel wird die Zahl 37 als Standardwert zurckgegeben, wenn der Eigenschaftsname nicht im Objekt vorhanden ist. Es wird der get() Handler verwendet.
const handler = {
get(obj, prop) {
return prop in obj ? obj[prop] : 37;
},
};
const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log("c" in p, p.c); // false, 37
In diesem Beispiel verwenden wir ein natives JavaScript-Objekt, an das unser Proxy alle Operationen weiterleiten wird, die darauf angewendet werden.
const target = {};
const p = new Proxy(target, {});
p.a = 37; // Operation forwarded to the target
console.log(target.a); // 37 (The operation has been properly forwarded!)
Beachten Sie, dass dieses "No-op" fr einfache JavaScript-Objekte funktioniert, aber nicht fr native Objekte wie DOM-Elemente, Map-Objekte oder alles, was interne Slots hat. Siehe keine Weiterleitung privater Felder fr weitere Informationen.
Ein Proxy ist weiterhin ein anderes Objekt mit einer anderen Identitt er ist ein Proxy, der zwischen dem umhllten Objekt und der Auenwelt operiert. Daher hat der Proxy keinen direkten Zugriff auf die privaten Elemente des Originalobjekts.
class Secret {
#secret;
constructor(secret) {
this.#secret = secret;
}
get secret() {
return this.#secret.replace(/\d+/, "[REDACTED]");
}
}
const secret = new Secret("123456");
console.log(secret.secret); // [REDACTED]
// Looks like a no-op forwarding...
const proxy = new Proxy(secret, {});
console.log(proxy.secret); // TypeError: Cannot read private member #secret from an object whose class did not declare it
Dies liegt daran, dass, wenn der get-Trap des Proxys aufgerufen wird, this-Wert der proxy anstelle des ursprnglichen secret ist, sodass #secret nicht zugnglich ist. Um dies zu beheben, verwenden Sie das ursprngliche secret als this:
const proxy = new Proxy(secret, {
get(target, prop, receiver) {
// By default, it looks like Reflect.get(target, prop, receiver)
// which has a different value of `this`
return target[prop];
},
});
console.log(proxy.secret);
Fr Methoden bedeutet dies, dass Sie den this-Wert der Methode auf das ursprngliche Objekt ebenfalls umleiten mssen:
class Secret {
#x = 1;
x() {
return this.#x;
}
}
const secret = new Secret();
const proxy = new Proxy(secret, {
get(target, prop, receiver) {
const value = target[prop];
if (value instanceof Function) {
return function (...args) {
return value.apply(this === receiver ? target : this, args);
};
}
return value;
},
});
console.log(proxy.x());
Einige native JavaScript-Objekte haben Eigenschaften, die als interne Slots bezeichnet werden und die vom JavaScript-Code nicht zugnglich sind. Zum Beispiel haben Map-Objekte einen internen Slot namens [[MapData]], der die Schlssel-Wert-Paare der Karte speichert. Daher knnen Sie nicht trivial einen Weiterleitungsproxy fr eine Karte erstellen:
const proxy = new Proxy(new Map(), {});
console.log(proxy.size); // TypeError: get size method called on incompatible Proxy
Sie mssen den oben illustrierten this-Wiederherstellungs-Proxy verwenden, um dies zu umgehen.
Mit einem Proxy knnen Sie leicht den bergebenen Wert fr ein Objekt validieren. Dieses Beispiel verwendet den set() Handler.
const validator = {
set(obj, prop, value) {
if (prop === "age") {
if (!Number.isInteger(value)) {
throw new TypeError("The age is not an integer");
}
if (value > 200) {
throw new RangeError("The age seems invalid");
}
}
// The default behavior to store the value
obj[prop] = value;
// Indicate success
return true;
},
};
const person = new Proxy({}, validator);
person.age = 100;
console.log(person.age); // 100
person.age = "young"; // Throws an exception
person.age = 300; // Throws an exception
In diesem Beispiel verwenden wir Proxy, um ein Attribut von zwei verschiedenen Elementen umzuschalten: Wenn wir das Attribut an einem Element setzen, wird das Attribut am anderen automatisch gelscht.
Wir erstellen ein view-Objekt, das ein Proxy fr ein Objekt mit einer selected-Eigenschaft ist. Der Proxy-Handler definiert den set() Handler.
Wenn wir ein HTML-Element view.selected zuweisen, wird das 'aria-selected'-Attribut des Elements auf true gesetzt. Wenn wir dann ein anderes Element view.selected zuweisen, wird das 'aria-selected'-Attribut dieses Elements auf true gesetzt und das vorherige Element's 'aria-selected'-Attribut wird automatisch auf false gesetzt.
const view = new Proxy(
{
selected: null,
},
{
set(obj, prop, newVal) {
const oldVal = obj[prop];
if (prop === "selected") {
if (oldVal) {
oldVal.setAttribute("aria-selected", "false");
}
if (newVal) {
newVal.setAttribute("aria-selected", "true");
}
}
// The default behavior to store the value
obj[prop] = newVal;
// Indicate success
return true;
},
},
);
const item1 = document.getElementById("item-1");
const item2 = document.getElementById("item-2");
// select item1:
view.selected = item1;
console.log(`item1: ${item1.getAttribute("aria-selected")}`);
// item1: true
// selecting item2 de-selects item1:
view.selected = item2;
console.log(`item1: ${item1.getAttribute("aria-selected")}`);
// item1: false
console.log(`item2: ${item2.getAttribute("aria-selected")}`);
// item2: true
Das products-Proxy-Objekt bewertet den bergebenen Wert und konvertiert ihn bei Bedarf in ein Array. Das Objekt untersttzt auch eine zustzliche Eigenschaft namens latestBrowser sowohl als Getter als auch als Setter.
const products = new Proxy(
{
browsers: ["Firefox", "Chrome"],
},
{
get(obj, prop) {
// An extra property
if (prop === "latestBrowser") {
return obj.browsers[obj.browsers.length - 1];
}
// The default behavior to return the value
return obj[prop];
},
set(obj, prop, value) {
// An extra property
if (prop === "latestBrowser") {
obj.browsers.push(value);
return true;
}
// Convert the value if it is not an array
if (typeof value === "string") {
value = [value];
}
// The default behavior to store the value
obj[prop] = value;
// Indicate success
return true;
},
},
);
console.log(products.browsers);
// ['Firefox', 'Chrome']
products.browsers = "Safari";
// pass a string (by mistake)
console.log(products.browsers);
// ['Safari'] <- no problem, the value is an array
products.latestBrowser = "Edge";
console.log(products.browsers);
// ['Safari', 'Edge']
console.log(products.latestBrowser);
// 'Edge'
| Spezifikation |
|---|
| ECMAScript 2027 LanguageSpecification # sec-proxy-objects |
Der Bauplan fr ein besseres Internet.
Teile dieses Inhalts sind 19982026 von einzelnen mozilla.org-Mitwirkenden. Inhalte sind verfgbar unter einer Creative-Commons-Lizenz.
| Web Proxy Viewer | New URL | Original Page |