Start · Sprachen · JavaScript · Referenz · Object.freeze()

Object.freeze()

Methode

Die statische Methode <code>Object.freeze()</code> friert ein Objekt ein, sodass es nicht mehr verändert werden kann.

Kategorie: method-property

Signatur

Object.freeze(obj)

Beschreibung

Die statische Methode Object.freeze() friert ein Objekt ein. Das Einfrieren eines Objekts verhindert Erweiterungen und macht bestehende Eigenschaften nicht schreibbar und nicht konfigurierbar. Ein eingefrorenes Objekt kann nicht mehr verändert werden: Neue Eigenschaften können nicht hinzugefügt, bestehende Eigenschaften nicht entfernt werden, ihre Aufzählbarkeit, Konfigurierbarkeit, Schreibbarkeit oder ihr Wert können nicht geändert werden, und der Prototype des Objekts kann nicht neu zugewiesen werden. freeze() gibt dasselbe Objekt zurück, das übergeben wurde.

Das Einfrieren eines Objekts ist die höchste Integritätsstufe, die JavaScript bietet.

Das Einfrieren eines Objekts entspricht dem Verhindern von Erweiterungen und dem anschließenden Ändern aller vorhandenen Deskriptor-Attribute configurable auf false — und bei Dateneigenschaften zusätzlich writable auf false. Zu den Eigenschaften eines eingefrorenen Objekts kann nichts hinzugefügt oder daraus entfernt werden. Jeder derartige Versuch schlägt fehl, entweder still oder durch Werfen einer TypeError-Ausnahme (am häufigsten, aber nicht ausschließlich im strict mode).

Bei Dateneigenschaften eines eingefrorenen Objekts können deren Werte nicht geändert werden, da die Attribute writable und configurable auf false gesetzt sind. Zugriffseigenschaften (Getter und Setter) funktionieren gleich — der vom Getter zurückgegebene Eigenschaftswert kann sich weiterhin ändern, und der Setter kann weiterhin aufgerufen werden, ohne Fehler zu werfen, wenn die Eigenschaft gesetzt wird. Beachten Sie, dass Werte, die Objekte sind, weiterhin verändert werden können, es sei denn, sie sind ebenfalls eingefroren. Als Objekt kann auch ein Array eingefroren werden; danach können seine Elemente nicht verändert und keine Elemente hinzugefügt oder entfernt werden.

Private elements sind keine Eigenschaften und haben kein Konzept von Property Descriptors. Das Einfrieren eines Objekts mit private elements verhindert nicht, dass die Werte dieser private elements geändert werden. (Das Einfrieren von Objekten ist meist als Sicherheitsmaßnahme gegen externen Code gedacht, aber externer Code kann ohnehin nicht auf private elements zugreifen.) Private elements können weder hinzugefügt noch aus dem Objekt entfernt werden, unabhängig davon, ob das Objekt eingefroren ist oder nicht.

freeze() gibt dasselbe Objekt zurück, das an die Funktion übergeben wurde. Es erstellt keine eingefrorene Kopie.

Ein TypedArray oder ein DataView mit Elementen verursacht einen TypeError, da diese Ansichten über den Speicher sind und definitiv weitere mögliche Probleme verursachen würden.

Beachten Sie, dass die drei Standardeigenschaften (buf.byteLength, buf.byteOffset und buf.buffer) schreibgeschützt sind (ebenso wie die eines ArrayBuffer oder SharedArrayBuffer), sodass es keinen Grund gibt, diese Eigenschaften einzufrieren zu versuchen.

Im Gegensatz zu Object.seal() werden bestehende Eigenschaften in mit Object.freeze() eingefrorenen Objekten unveränderlich, und Dateneigenschaften können nicht neu zugewiesen werden.

Parameter

Name Typ Default Beschreibung
$obj Pflicht Object Das einzufrierende Objekt.

Rückgabewert

Typ
Object
Beschreibung
Das Objekt, das an die Funktion übergeben wurde.

Beispiele

Objekte einfrieren

const obj = {
  prop() {},
  foo: "bar",
};

// Vor dem Einfrieren: neue Eigenschaften können hinzugefügt werden,
// und vorhandene Eigenschaften können geändert oder entfernt werden
obj.foo = "baz";
obj.lumpy = "woof";
delete obj.prop;

// Einfrieren.
const o = Object.freeze(obj);

// Der Rückgabewert ist genau dasselbe Objekt, das wir übergeben haben.
o === obj; // true

// Das Objekt ist nun eingefroren.
Object.isFrozen(obj); // === true

// Jetzt schlagen alle Änderungen fehl
obj.foo = "quux"; // tut still nichts
// fügt die Eigenschaft still nicht hinzu
obj.quaxxor = "the friendly duck";

// Im strict mode werfen solche Versuche TypeErrors
function fail() {
  "use strict";
  obj.foo = "sparky"; // wirft einen TypeError
  delete obj.foo; // wirft einen TypeError
  delete obj.quaxxor; // gibt true zurück, da das Attribut 'quaxxor' nie hinzugefügt wurde
  obj.sparky = "arf"; // wirft einen TypeError
}

fail();

// Versuchte Änderungen über Object.defineProperty;
// beide Anweisungen unten werfen einen TypeError.
Object.defineProperty(obj, "ohai", { value: 17 });
Object.defineProperty(obj, "foo", { value: "eit" });

// Es ist auch unmöglich, den Prototype zu ändern
// beide Anweisungen unten werfen einen TypeError.
Object.setPrototypeOf(obj, { x: 20 });
obj.__proto__ = { x: 20 };

Arrays einfrieren

const a = [0];
Object.freeze(a); // Das Array kann jetzt nicht mehr verändert werden.

a[0] = 1; // schlägt still fehl

// Im strict mode wirft ein solcher Versuch einen TypeError
function fail() {
  "use strict";
  a[0] = 1;
}

fail();

// Versuch zu pushen
a.push(2); // wirft einen TypeError

Einfrieren ist flach

const obj1 = {
  internal: {},
};

Object.freeze(obj1);
obj1.internal.a = "value";

obj1.internal.a; // 'value'

Deep Freezing

const employee = {
  name: "Mayank",
  designation: "Developer",
  address: {
    street: "Rohini",
    city: "Delhi",
  },
};

Object.freeze(employee);

employee.name = "Dummy"; // schlägt im non-strict mode still fehl
employee.address.city = "Noida"; // Attribute des Kindobjekts können verändert werden

console.log(employee.address.city); // "Noida"

deepFreeze-Implementierung

function deepFreeze(object) {
  // Die auf dem Objekt definierten Eigenschaftsnamen abrufen
  const propNames = Reflect.ownKeys(object);

  // Eigenschaften einfrieren, bevor das Objekt selbst eingefroren wird
  for (const name of propNames) {
    const value = object[name];

    if ((value && typeof value === "object") || typeof value === "function") {
      deepFreeze(value);
    }
  }

  return Object.freeze(object);
}

const obj2 = {
  internal: {
    a: null,
  },
};

deepFreeze(obj2);

obj2.internal.a = "anotherValue"; // schlägt im non-strict mode still fehl
obj2.internal.a; // null

TypedArray und DataView einfrieren

Object.freeze(new Uint8Array(0)); // Keine Elemente
// Uint8Array []

Object.freeze(new Uint8Array(1)); // Hat Elemente
// TypeError: Cannot freeze array buffer views with elements

Object.freeze(new DataView(new ArrayBuffer(32))); // Keine Elemente
// DataView {}

Object.freeze(new Float64Array(new ArrayBuffer(64), 32, 0)); // Keine Elemente
// Float64Array []

Object.freeze(new Float64Array(new ArrayBuffer(64), 32, 2)); // Hat Elemente
// TypeError: Cannot freeze array buffer views with elements

// Wichtig · Fallstricke

Das eingefrorene Objekt ist unveränderlich (immutable), jedoch nicht notwendigerweise konstant, da freeze() nur flach (shallow) wirkt. Um ein konstantes Objekt zu erreichen, muss der gesamte Referenzgraph nur unveränderliche eingefrorene Objekte referenzieren. Bei zyklischen Referenzen kann deepFreeze() in eine Endlosschleife geraten — Funktionen, die mit der function-Syntax erstellt wurden, haben durch prototype.constructor standardmäßig Zyklen.