Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten.Erfahre mehr über dieses Experiment.
Object.defineProperty()
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since Juli 2015.
DieObject.defineProperty() statische Methode definiert eine neue Eigenschaft direkt auf einem Objekt oder ändert eine bestehende Eigenschaft auf einem Objekt und gibt das Objekt zurück.
In diesem Artikel
Probieren Sie es aus
const object = {};Object.defineProperty(object, "foo", { value: 42, writable: false,});object.foo = 77;// Throws an error in strict modeconsole.log(object.foo);// Expected output: 42Syntax
Object.defineProperty(obj, prop, descriptor)Parameter
objDas Objekt, auf dem die Eigenschaft definiert werden soll.
propEin String oder
Symbol, der den Schlüssel der zu definierenden oder zu ändernden Eigenschaft spezifiziert.descriptorDer Deskriptor für die definierte oder geänderte Eigenschaft.
Rückgabewert
Das der Funktion übergebene Objekt, bei dem die angegebene Eigenschaft hinzugefügt oder geändert wurde.
Beschreibung
Object.defineProperty() ermöglicht eine präzise Ergänzung oder Änderung einer Eigenschaft auf einem Objekt. Die normale Eigenschaftszuweisung durchZuweisung erstellt Eigenschaften, die bei der Eigenschaftsaufzählung sichtbar sind (for...in,Object.keys(), etc.), deren Werte geändert werden können und diegelöscht werden können. Diese Methode erlaubt es, diese zusätzlichen Details von ihren Standardeinstellungen zu ändern. Standardmäßig sind Eigenschaften, die mitObject.defineProperty() hinzugefügt werden, nicht schreibbar, nicht aufzählbar und nicht konfigurierbar. Darüber hinaus verwendetObject.defineProperty() die interne Methode[[DefineOwnProperty]], anstatt[[Set]], sodass es keineSetter aufruft, selbst wenn die Eigenschaft bereits vorhanden ist.
Eigenschaftsdeskriptoren in Objekten gibt es in zwei Hauptarten: Daten-Deskriptoren und Accessor-Deskriptoren. EinDaten-Deskriptor ist eine Eigenschaft mit einem Wert, der möglicherweise schreibbar ist oder nicht. EinAccessor-Deskriptor ist eine Eigenschaft, die durch ein Getter-Setter-Paar von Funktionen beschrieben wird. Ein Deskriptor muss eine dieser beiden Arten sein; er kann nicht beides sein.
Sowohl Daten- als auch Accessor-Deskriptoren sind Objekte. Sie teilen sich die folgenden optionalen Schlüssel (bitte beachten: die hier erwähntenStandardeinstellungen gelten bei der Definition von Eigenschaften mitObject.defineProperty()):
configurablewenn dies auf
falsegesetzt ist,- kann der Typ dieser Eigenschaft nicht zwischen Daten- und Accessor-Eigenschaft geändert werden, und
- die Eigenschaft kann nicht gelöscht werden, und
- andere Attribute seines Deskriptors können nicht geändert werden (jedoch, wenn es sich um einen Daten-Deskriptor mit
writable: truehandelt, kann dervaluegeändert werden undwritablekann auffalsegeändert werden).
Standard ist
false.enumerabletruenur dann, wenn diese Eigenschaft bei der Aufzählung der Eigenschaften auf dem entsprechenden Objekt sichtbar wird.Standard istfalse.
EinDaten-Deskriptor hat auch die folgenden optionalen Schlüssel:
valueDer mit der Eigenschaft verknüpfte Wert. Kann jeder gültige JavaScript-Wert sein (Zahl, Objekt, Funktion, etc.).Standard ist
undefined.writabletrue, wenn der mit der Eigenschaft verknüpfte Wert mit einemZuweisungsoperator geändert werden kann.Standard istfalse.
EinAccessor-Deskriptor hat auch die folgenden optionalen Schlüssel:
getEine Funktion, die als Getter für die Eigenschaft dient, oder
undefined, wenn es keinen Getter gibt. Wenn auf die Eigenschaft zugegriffen wird, wird diese Funktion ohne Argumente und mitthisauf das Objekt gesetzt, durch das die Eigenschaft angesprochen wird (dies muss nicht das Objekt sein, auf dem die Eigenschaft definiert ist, durch Vererbung). Der Rückgabewert wird als Wert der Eigenschaft verwendet.Standard istundefined.setEine Funktion, die als Setter für die Eigenschaft dient, oder
undefined, wenn es keinen Setter gibt. Wenn der Eigenschaft ein Wert zugewiesen wird, wird diese Funktion mit einem Argument (dem der Eigenschaft zugewiesenen Wert) und mitthisauf das Objekt gesetzt, durch das die Eigenschaft zugewiesen wird, aufgerufen.Standard istundefined.
Wenn ein Deskriptor keinen dervalue,writable,get undset Schlüssel hat, wird er als Daten-Deskriptor behandelt. Wenn ein Deskriptor sowohl ein Daten-Deskriptor (weil ervalue oderwritable hat) als auch ein Accessor-Deskriptor (weil erget oderset hat) ist, wird eine Ausnahme ausgelöst.
Diese Attribute sind nicht zwangsläufig die eigenen Eigenschaften des Deskriptors. Geerbte Eigenschaften werden ebenfalls berücksichtigt. Um sicherzustellen, dass diese Standardeinstellungen beibehalten werden, können Sie bestehende Objekte in der Prototypenkette des Deskriptorobjekts im Voraus einfrieren, alle Optionen explizit angeben oder einnull-Prototyp-Objekt erstellen.
const obj = {};// 1. Using a null prototype: no inherited propertiesconst descriptor = Object.create(null);descriptor.value = "static";// not enumerable, not configurable, not writable as defaultsObject.defineProperty(obj, "key", descriptor);// 2. Being explicit by using a throw-away object literal with all attributes presentObject.defineProperty(obj, "key2", { enumerable: false, configurable: false, writable: false, value: "static",});// 3. Prevents adding or removing the object prototype properties// (value, get, set, enumerable, writable, configurable)Object.freeze(Object.prototype);Wenn die Eigenschaft bereits existiert, versuchtObject.defineProperty(), die Eigenschaft gemäß den Werten im Deskriptor und der aktuellen Konfiguration der Eigenschaft zu ändern.
Wenn das alte Deskriptor seineconfigurable Eigenschaft auffalse gesetzt hat, wird die Eigenschaft alsnicht konfigurierbar bezeichnet. Es ist nicht möglich, irgendwelche Attribute einer nicht konfigurierbaren Accessor-Eigenschaft zu ändern, und es ist nicht möglich, zwischen Daten- und Accessor-Eigenschaftstypen zu wechseln. Für Daten-Eigenschaften mitwritable: true ist es möglich, den Wert zu ändern und daswritable Attribut vontrue auffalse zu ändern. EinTypeError wird ausgelöst, wenn versucht wird, nicht konfigurierbare Eigenschaftenattribute zu ändern (außervalue undwritable, falls erlaubt), außer wenn ein Wert definiert wird, der derselbe wie der ursprüngliche Wert auf einer Daten-Eigenschaft ist.
Wenn die aktuelle Eigenschaft konfigurierbar ist, löscht die Definition eines Attributs aufundefined effektiv das Attribut. Zum Beispiel, wenno.k eine Accessor-Eigenschaft ist, entferntObject.defineProperty(o, "k", { set: undefined }) den Setter, wodurchk nur einen Getter hat und somit schreibgeschützt wird. Wenn ein Attribut im neuen Deskriptor fehlt, behält es den Wert des alten Deskriptor-Attributs (es wird nicht implizit aufundefined zurückgesetzt). Es ist möglich, zwischen Daten- und Accessor-Eigenschaften zu wechseln, indem man einen Deskriptor eines anderen "Typs" angibt. Zum Beispiel, wenn der neue Deskriptor ein Daten-Deskriptor ist (mitvalue oderwritable), werden dieget undset Attribute des ursprünglichen Deskriptors beide entfernt.
Beispiele
>Erstellen einer Eigenschaft
Wenn die angegebene Eigenschaft im Objekt nicht existiert, erstelltObject.defineProperty() eine neue Eigenschaft wie beschrieben. Felder können im Deskriptor weggelassen werden und Standardwerte für diese Felder werden eingefügt.
const o = {}; // Creates a new object// Example of an object property added// with defineProperty with a data property descriptorObject.defineProperty(o, "a", { value: 37, writable: true, enumerable: true, configurable: true,});// 'a' property exists in the o object and its value is 37// Example of an object property added// with defineProperty with an accessor property descriptorlet bValue = 38;Object.defineProperty(o, "b", { get() { return bValue; }, set(newValue) { bValue = newValue; }, enumerable: true, configurable: true,});o.b; // 38// 'b' property exists in the o object and its value is 38// The value of o.b is now always identical to bValue,// unless o.b is redefined// You cannot try to mix both:Object.defineProperty(o, "conflict", { value: 0x9f91102, get() { return 0xdeadbeef; },});// throws a TypeError: value appears// only in data descriptors,// get appears only in accessor descriptorsÄndern einer Eigenschaft
Beim Ändern einer vorhandenen Eigenschaft bestimmt die aktuelle Eigenschaftskonfiguration, ob der Operator erfolgreich ist, nichts tut oder einenTypeError auslöst.
Schreibbares Attribut
Wenn daswritable Eigenschaftsattributfalse ist, wird die Eigenschaft als "nicht-schreibbar" bezeichnet. Sie kann nicht neu zugewiesen werden. Der Versuch, einer nicht-schreibbaren Eigenschaft einen neuen Wert zuzuweisen, ändert sie nicht und führt zu einem Fehler imstriktem Modus.
const o = {}; // Creates a new objectObject.defineProperty(o, "a", { value: 37, writable: false,});console.log(o.a); // 37o.a = 25; // No error thrown// (it would throw in strict mode,// even if the value had been the same)console.log(o.a); // 37; the assignment didn't work// strict mode(() => { "use strict"; const o = {}; Object.defineProperty(o, "b", { value: 2, writable: false, }); o.b = 3; // throws TypeError: "b" is read-only return o.b; // returns 2 without the line above})();Aufzählbares Attribut
Dasenumerable Eigenschaftsattribut definiert, ob die Eigenschaft vonObject.assign() oder demSpread Operator berücksichtigt wird. Für nicht-Symbol Eigenschaften definiert es auch, ob sie in einerfor...in Schleife undObject.keys() angezeigt werden oder nicht. Für weitere Informationen sieheAufzählbarkeit und Eigentum von Eigenschaften.
const o = {};Object.defineProperty(o, "a", { value: 1, enumerable: true,});Object.defineProperty(o, "b", { value: 2, enumerable: false,});Object.defineProperty(o, "c", { value: 3,}); // enumerable defaults to falseo.d = 4; // enumerable defaults to true when creating a property by setting itObject.defineProperty(o, Symbol.for("e"), { value: 5, enumerable: true,});Object.defineProperty(o, Symbol.for("f"), { value: 6, enumerable: false,});for (const i in o) { console.log(i);}// Logs 'a' and 'd' (always in that order)Object.keys(o); // ['a', 'd']o.propertyIsEnumerable("a"); // trueo.propertyIsEnumerable("b"); // falseo.propertyIsEnumerable("c"); // falseo.propertyIsEnumerable("d"); // trueo.propertyIsEnumerable(Symbol.for("e")); // trueo.propertyIsEnumerable(Symbol.for("f")); // falseconst p = { ...o };p.a; // 1p.b; // undefinedp.c; // undefinedp.d; // 4p[Symbol.for("e")]; // 5p[Symbol.for("f")]; // undefinedKonfigurierbares Attribut
Dasconfigurable Attribut steuert, ob die Eigenschaft aus dem Objekt gelöscht werden kann und ob ihre Attribute (außervalue undwritable) geändert werden können.
Dieses Beispiel zeigt eine nicht konfigurierbare Accessor-Eigenschaft.
const o = {};Object.defineProperty(o, "a", { get() { return 1; }, configurable: false,});Object.defineProperty(o, "a", { configurable: true,}); // throws a TypeErrorObject.defineProperty(o, "a", { enumerable: true,}); // throws a TypeErrorObject.defineProperty(o, "a", { set() {},}); // throws a TypeError (set was undefined previously)Object.defineProperty(o, "a", { get() { return 1; },}); // throws a TypeError// (even though the new get does exactly the same thing)Object.defineProperty(o, "a", { value: 12,}); // throws a TypeError// ('value' can be changed when 'configurable' is false, but only when the property is a writable data property)console.log(o.a); // 1delete o.a; // Nothing happens; throws an error in strict modeconsole.log(o.a); // 1Wenn dasconfigurable Attribut vono.atrue gewesen wäre, würden keine Fehler ausgelöst werden und die Eigenschaft würde am Ende gelöscht werden.
Dieses Beispiel zeigt eine nicht konfigurierbare aber schreibbare Daten-Eigenschaft. Dervalue der Eigenschaft kann immer noch geändert werden, undwritable kann immer noch vontrue auffalse umgeschaltet werden.
const o = {};Object.defineProperty(o, "b", { writable: true, configurable: false,});console.log(o.b); // undefinedObject.defineProperty(o, "b", { value: 1,}); // Even when configurable is false, because the object is writable, we may still replace the valueconsole.log(o.b); // 1o.b = 2; // We can change the value with assignment operators as wellconsole.log(o.b); // 2// Toggle the property's writabilityObject.defineProperty(o, "b", { writable: false,});Object.defineProperty(o, "b", { value: 1,}); // TypeError: because the property is neither writable nor configurable, it cannot be modified// At this point, there's no way to further modify 'b'// or restore its writabilityDieses Beispiel zeigt eine konfigurierbare, aber nicht schreibbare Daten-Eigenschaft. Dervalue der Eigenschaft kann immer noch mitdefineProperty ersetzt werden (aber nicht mit Zuweisungsoperatoren), undwritable kann umgeschaltet werden.
const o = {};Object.defineProperty(o, "b", { writable: false, configurable: true,});Object.defineProperty(o, "b", { value: 1,}); // We can replace the value with definePropertyconsole.log(o.b); // 1o.b = 2; // throws TypeError in strict mode: cannot change a non-writable property's value with assignmentDieses Beispiel zeigt eine nicht konfigurierbare und nicht schreibbare Daten-Eigenschaft. Es gibt keine Möglichkeit, irgendein Attribut der Eigenschaft zu aktualisieren, einschließlich ihresvalue.
const o = {};Object.defineProperty(o, "b", { writable: false, configurable: false,});Object.defineProperty(o, "b", { value: 1,}); // TypeError: the property cannot be modified because it is neither writable nor configurable.Hinzufügen von Eigenschaften und Standardeinstellungen
Es ist wichtig, die Art und Weise zu berücksichtigen, wie Standardwerte von Attributen angewendet werden. Es gibt oft einen Unterschied zwischen der Verwendung vonEigenschafts-Accessoren zur Zuweisung eines Wertes und der Verwendung vonObject.defineProperty(), wie im folgenden Beispiel gezeigt.
const o = {};o.a = 1;// is equivalent to:Object.defineProperty(o, "a", { value: 1, writable: true, configurable: true, enumerable: true,});// On the other hand,Object.defineProperty(o, "a", { value: 1 });// is equivalent to:Object.defineProperty(o, "a", { value: 1, writable: false, configurable: false, enumerable: false,});Benutzerdefinierte Setter und Getter
Das folgende Beispiel zeigt, wie ein sich selbst archivierendes Objekt implementiert werden kann. Wenn dietemperature Eigenschaft gesetzt wird, erhält dasarchive Array einen Protokolleintrag.
function Archiver() { let temperature = null; const archive = []; Object.defineProperty(this, "temperature", { get() { console.log("get!"); return temperature; }, set(value) { temperature = value; archive.push({ val: temperature }); }, }); this.getArchive = () => archive;}const arc = new Archiver();arc.temperature; // 'get!'arc.temperature = 11;arc.temperature = 13;arc.getArchive(); // [{ val: 11 }, { val: 13 }]In diesem Beispiel gibt ein Getter immer denselben Wert zurück.
const pattern = { get() { return "I always return this string, whatever you have assigned"; }, set() { this.myName = "this is my name string"; },};function TestDefineSetAndGet() { Object.defineProperty(this, "myProperty", pattern);}const instance = new TestDefineSetAndGet();instance.myProperty = "test";console.log(instance.myProperty);// I always return this string, whatever you have assignedconsole.log(instance.myName); // this is my name stringVererbung von Eigenschaften
Wenn eine Accessor-Eigenschaft vererbt wird, werden ihreget undset Methoden aufgerufen, wenn die Eigenschaft in Nachkommenobjekten angesprochen oder geändert wird. Wenn diese Methoden eine Variable verwenden, um den Wert zu speichern, wird dieser Wert von allen Objekten geteilt.
function MyClass() {}let value;Object.defineProperty(MyClass.prototype, "x", { get() { return value; }, set(x) { value = x; },});const a = new MyClass();const b = new MyClass();a.x = 1;console.log(b.x); // 1Dies kann behoben werden, indem der Wert in einer anderen Eigenschaft gespeichert wird. Inget undset Methoden zeigtthis auf das Objekt, das verwendet wird, um die Eigenschaft anzusprechen oder zu ändern.
function MyClass() {}Object.defineProperty(MyClass.prototype, "x", { get() { return this.storedX; }, set(x) { this.storedX = x; },});const a = new MyClass();const b = new MyClass();a.x = 1;console.log(b.x); // undefinedIm Gegensatz zu Accessor-Eigenschaften werden Daten-Eigenschaften immer auf dem Objekt selbst und nicht auf einem Prototyp gesetzt. Wenn jedoch eine nicht schreibbare Daten-Eigenschaft vererbt wird, wird immer noch verhindert, dass sie auf dem Objekt geändert wird.
function MyClass() {}MyClass.prototype.x = 1;Object.defineProperty(MyClass.prototype, "y", { writable: false, value: 1,});const a = new MyClass();a.x = 2;console.log(a.x); // 2console.log(MyClass.prototype.x); // 1a.y = 2; // Ignored, throws in strict modeconsole.log(a.y); // 1console.log(MyClass.prototype.y); // 1Spezifikationen
| Specification |
|---|
| ECMAScript® 2026 Language Specification> # sec-object.defineproperty> |