Signatur
Beschreibung
Object.defineProperties() ist die Mehrfach-Variante von Object.defineProperty(). Statt einer einzelnen Eigenschaft übergibt man ein Objekt, dessen eigene aufzählbare Schlüssel die Namen der zu definierenden Eigenschaften sind. Die zugehörigen Werte sind Eigenschafts-Deskriptoren. Damit lassen sich Attribute wie writable, enumerable und configurable oder Zugriffsmethoden (get/set) genau steuern.
Deskriptoren gibt es in zwei Arten: Daten-Deskriptoren (value, writable) und Accessor-Deskriptoren (get, set). Beide können zusätzlich enumerable und configurable enthalten. Einen Deskriptor, der beide Arten mischt (z. B. value und get), weist die Methode mit einem TypeError ab.
Typische Einsatzfälle sind unveränderliche Konstanten an Objekten, berechnete Eigenschaften mit Gettern und Settern, versteckte (nicht aufzählbare) Hilfseigenschaften in Bibliotheken und das Kopieren von Eigenschaften einschließlich Accessoren, zusammen mit Object.getOwnPropertyDescriptors().
Wichtig: Attribute, die im Deskriptor fehlen, erhalten bei neu angelegten Eigenschaften den Standardwert false bzw. undefined. Das ist anders als bei einer normalen Zuweisung (obj.x = 1). Dort sind alle Flags true.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $obj Pflicht | Object | Das Zielobjekt, an dem die Eigenschaften definiert oder geändert werden. Ist es kein Objekt (z. B. eine primitive Zahl), wird ein TypeError geworfen. |
|
| $props Pflicht | Object | Ein Objekt, dessen eigene aufzählbare Schlüssel (Strings und Symbole) die Eigenschaftsnamen sind. Jeder Wert ist ein Deskriptor mit den optionalen Feldern value, writable, get, set, enumerable und configurable. |
Rückgabewert
obj, das übergeben wurde (keine Kopie), jetzt mit den neuen oder geänderten Eigenschaften.Beispiele
Konstanten und berechnete Eigenschaft an einem Konfigurationsobjekt
const config = {};
Object.defineProperties(config, {
apiVersion: {
value: 'v2',
enumerable: true
// writable und configurable sind standardmäßig false
},
baseUrl: {
value: 'https://api.example.com',
enumerable: true
},
endpoint: {
get() {
return `${this.baseUrl}/${this.apiVersion}`;
},
enumerable: true
}
});
config.apiVersion = 'v3'; // wird im Sloppy Mode stillschweigend ignoriert
console.log(config.endpoint);
console.log(Object.keys(config));
Getter/Setter mit Validierung und verstecktem internem Zustand
'use strict';
const temperatur = {};
Object.defineProperties(temperatur, {
_celsius: {
value: 0,
writable: true,
enumerable: false // taucht nicht in JSON/Object.keys auf
},
celsius: {
get() { return this._celsius; },
set(wert) {
if (typeof wert !== 'number') throw new TypeError('Zahl erwartet');
this._celsius = wert;
},
enumerable: true
},
fahrenheit: {
get() { return this._celsius * 9 / 5 + 32; },
set(wert) { this._celsius = (wert - 32) * 5 / 9; },
enumerable: true
}
});
temperatur.fahrenheit = 212;
console.log(temperatur.celsius);
console.log(JSON.stringify(temperatur));
Objekt inklusive Getter/Setter vollständig kopieren
const quelle = {
vorname: 'Ada',
nachname: 'Lovelace',
get vollerName() {
return `${this.vorname} ${this.nachname}`;
}
};
// Object.assign würde den Getter nur auswerten und den Wert kopieren
const kopie = Object.defineProperties(
{},
Object.getOwnPropertyDescriptors(quelle)
);
kopie.vorname = 'Grace';
console.log(kopie.vollerName);
console.log(typeof Object.getOwnPropertyDescriptor(kopie, 'vollerName').get);
Fehler durch ungültigen Deskriptor
try {
Object.defineProperties({}, {
kaputt: {
value: 42,
get() { return 42; } // value + get ist nicht erlaubt
}
});
} catch (err) {
console.log(err instanceof TypeError);
}
// Wichtig · Fallstricke
- Andere Standardwerte: Fehlen
writable,enumerableoderconfigurable, sind sie bei neuen Eigenschaftenfalse. Eine so definierte Eigenschaft ist also standardmäßig schreibgeschützt, unsichtbar fürfor...in,Object.keys()undJSON.stringify()und lässt sich nicht löschen. - Stilles Scheitern: Schreibzugriffe auf nicht beschreibbare Eigenschaften werden im Sloppy Mode ohne Meldung ignoriert. Nur im Strict Mode gibt es einen
TypeError. - Nicht atomar: Die Deskriptoren werden zuerst alle gelesen und geprüft, dann der Reihe nach angewendet. Scheitert eine Definition, etwa weil eine vorhandene Eigenschaft
configurable: falseist, wirft die Methode einenTypeError. Bereits angewendete Eigenschaften bleiben dann bestehen. - Nicht konfigurierbare Eigenschaften kann man nicht umdefinieren. Einzige Ausnahme:
writabledarf noch vontrueauffalsewechseln, undvaluedarf man ändern, solange die Eigenschaft beschreibbar ist. - Aus
propswerden nur eigene aufzählbare Schlüssel berücksichtigt, auch Symbole. Geerbte Eigenschaften des Deskriptor-Objekts gelten nicht als Eigenschaftsnamen. Die Deskriptoren selbst werden dagegen samt geerbter Felder gelesen, deshalb istObject.create(null)oder ein einfaches Objektliteral die sichere Wahl. - Nicht erweiterbare Objekte: Bei Objekten nach
Object.freeze(),Object.seal()oderObject.preventExtensions()scheitert das Hinzufügen neuer Eigenschaften mit einemTypeError. - Performance: Accessor-Eigenschaften und häufiges Umdefinieren können JIT-Optimierungen stören. In Hot Paths besser normale Eigenschaften oder Klassen mit
get/setverwenden. - Kompatibilität: Seit ES5 in allen modernen Browsern und in Node.js verfügbar. Nur der IE8 hatte eine fehlerhafte Teilunterstützung.