Object.freeze()

Metoda Object.freeze() "zamra┼╝a" obiekt, tzn. uniemo┼╝liwia dodawania nowych w┼éa┼Ťciwo┼Ťci do obiektu; uniemo┼╝liwia usuwanie istniej─ůcych w┼éa┼Ťciwo┼Ťci; uniemo┼╝liwia zmian─Ö istniej─ůcych w┼éa┼Ťciwo┼Ťci; oraz uniemo┼╝liwia zmian─Ö prototypu obiektu. W efekcie obiekt jest naprawd─Ö sta┼éy. Metoda zwraca obiekt w stanie "zamro┼╝onym".
 

Składnia

Object.freeze(obj)

Argumenty

obj
Obiekt kt├│ry ma zosta─ç "zamro┼╝ony".

Zwracana warto┼Ť─ç

"Zamro┼╝ony" obiekt.

Opis

Nic nie mo┼╝e zosta─ç dodane ani usuni─Öte z "zamro┼╝onego" obiektu. Ka┼╝da pr├│ba tego wywo┼éa b┼é─ůd, albo po cichu, albo rzucaj─ůc wyj─ůtek TypeError(zawzwyczaj, cho─ç nie zawsze, w przypadku u┼╝ywania strict mode).

Nie ma mo┼╝liwo┼Ťci zmiany warto┼Ťci w┼éa┼Ťciwo┼Ťci obiektu. Metody dost─Öpu (gettery i settery) dzia┼éaj─ů bez zmian (sprawiaj─ů wra┼╝enie skutecznej zmiany w┼éa┼Ťciwo┼Ťci obiektu). Zwr├│─ç uwag─Ö na to, ┼╝e warto┼Ťci, kt├│re s─ů obiektami w dalszym ci─ůgu mog─ů by─ç modyfikowane, chyba ┼╝e r├│wnie┼╝ s─ů "zamro┼╝one". Z uwagi na to, ┼╝e Tablica (Array) jest obiektem, r├│wnie┼╝ mo┼╝e zosta─ç zamro┼╝ona co uniemo┼╝liwi zmian─Ö jej element├│w, ich usuwanie oraz dodawanie nowych. 

Przykłady

 

Zamra┼╝anie Obiekt├│w

 

var obj = {
  prop: function() {},
  foo: 'bar'
};

// Nowe w┼éa┼Ťciwo┼Ťci mog─ů by─ç dodawane, istniej─ůce mog─ů by─ç zmieniane oraz usuwane
obj.foo = 'baz';
obj.lumpy = 'woof';
delete obj.prop;

// Zar├│wno obiekt przekazywany w funkcji freeze() jak i obiekt zwracany bed─ů "zamro┼╝one"
// Nie ma potrzeby przypisywania zwracanego obiektu do zmiennej je┼Ťli chcemy tylko "zamrozi─ç" obiekt przekazywany w funkcji
var o = Object.freeze(obj);

o === obj; // true
Object.isFrozen(obj); // === true

// Teraz wszelkie zmiany s─ů niemo┼╝liwe
obj.foo = 'quux'; // brak rezultatu nieskutkuj─ůcy wy┼Ťwietleniem b┼é─Ödu
obj.quaxxor = 'the friendly duck'; // brak rezultatu nieskutkuj─ůcy wy┼Ťwietleniem b┼é─Ödu

// przy strict mode tego typu pr├│by spowoduj─ů wy┼Ťwietlenie komunikatu o b┼é─Ödzie
function fail(){
  'use strict';
  obj.foo = 'sparky'; // TypeError
  delete obj.quaxxor; // TypeError
  obj.sparky = 'arf'; // TypeError
}

fail();

// Pr├│by zmian poprzez Object.defineProperty spowoduj─ů wy┼Ťwietlenie komunikatu o b┼é─Ödzie
Object.defineProperty(obj, 'ohai', { value: 17 }); // TypeError
Object.defineProperty(obj, 'foo', { value: 'eit' }); // TypeError

// Niemo┼╝liwa jest r├│wnie┼╝ zmiana prototypu obiektu. Obie instrukcje poni┼╝ej wygeneruj─ů b┼é─ůd
Object.setPrototypeOf(obj, { x: 20})
obj.__proto__ = { x: 20}

Zamra┼╝anie Tablic (Array)

 

let a = [0];
Object.freeze(a); // Tablica nie mo┼╝e by─ç teraz modyfikowana

a[0]=1; // brak rezultatu nieskutkuj─ůcy wy┼Ťwietleniem b┼é─Ödu
a.push(2); // brak rezultatu nieskutkuj─ůcy wy┼Ťwietleniem b┼é─Ödu

// przy strict mode tego typu pr├│by spowoduj─ů wy┼Ťwietlenie komunikatu o b┼é─Ödzie TypeErrors
function fail() {
  "use strict"
  a[0] = 1;
  a.push(2);
}

fail();

"Zamro┼╝ony" obiekt jest niemutowalny. Nie jest on jednak sta┼é─ů. Obrazuje to poni┼╝szy przyk┼éad.

obj1 = {
  internal: {}
};

Object.freeze(obj1);
obj1.internal.a = 'aValue';

obj1.internal.a // 'aValue'

 

To be a constant object, the entire reference graph (direct and indirect references to other objects) must reference only immutable frozen objects.  The object being frozen is said to be immutable because the entire object state (values and references to other objects) within the whole object is fixed.  Note that strings, numbers, and booleans are always immutable and that Functions and Arrays are objects. 

To make an object constant, recursively freeze each property which is of type object (deep freeze).  Use the pattern on a case-by-case basis based on your design when you know the object contains no cycles in the reference graph, otherwise an endless loop will be triggered.   An enhancement to deepFreeze() would be to have an internal function that receives a path (e.g. an Array) argument so you can supress calling deepFreeze() recursively when an object is in the process of being made constant.  You still run a risk of freezing an object that shouldn't be frozen, such as [window].

// To do so, we use this function.
function deepFreeze(obj) {

  // Retrieve the property names defined on obj
  var propNames = Object.getOwnPropertyNames(obj);

  // Freeze properties before freezing self
  propNames.forEach(function(name) {
    var prop = obj[name];

    // Freeze prop if it is an object
    if (typeof prop == 'object' && prop !== null)
      deepFreeze(prop);
  });

  // Freeze self (no-op if already frozen)
  return Object.freeze(obj);
}

obj2 = {
  internal: {}
};

deepFreeze(obj2);
obj2.internal.a = 'anotherValue';
obj2.internal.a; // unde

 

 

Notes

In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. In ES2015, a non-object argument will be treated as if it were a frozen ordinary object, and be simply returned.

> Object.freeze(1)
TypeError: 1 is not an object // ES5 code

> Object.freeze(1)
1                             // ES2015 code

Specifications

Browser compatibility

BCD tables only load in the browser

See also