Ostatnio przypomniałem podstawy związane z obiektami w JavaScripcie i opisałem nowe sposoby na definiowanie własności obiektów. Dziś druga część nowości ES5 związanych z obiektem Object
– zajmiemy się mrożeniem, pieczętowaniem i uniemożliwianiem rozszerzania obiektów.
ECMAScript 5: Ograniczanie możliwości modyfikacji obiektów
Mamy już zdefiniowane (w dotychczasowy sposób lub za pomocą defineProperty()
) własności obiektu, ale chcielibyśmy uniemożliwić dodawanie doń nowych własności. Może nasz obiekt zawiera pewne konkretne rzeczy, od których konkretnej liczby zależy działanie innego kodu? Albo po prostu nie chcemy, żeby ktoś zaśmiecał nam nasz obiekt innymi danymi? Jak to zrobić?
ES5 (a za nim JS 1.8.5) wprowadza funkcję Object.preventExtensions(obj)
. Blokuje ona możliwość dodawania nowych własności do obiektu przekazanego jej jako argument. W dalszym ciągu jednakże można własności usuwać oraz modyfikować ich deskryptory.
var obj = { a: 5, b: 7 }; Object.preventExtensions(obj); obj.a = 31337; // zmiana wartości: zadziała delete obj.b; // usunięcie własności: zadziała obj.c = 42; // dodanie własności: silent failure; w strict: TypeError
Warto jednak pamiętać, że w dalszym ciągu będzie można dodawać własności do tych obiektów znajdujących się ponad obj w łańcuchu prototypów.
Funkcja Object.isExtensible(obj)
zwróci informację o tym, czy obiekt jest rozszerzalny. Jej wynikiem będzie false
, jeśli na danym obiekcie wywołana została metoda Object.preventExtensions()
, a true
w przeciwnym przypadku (zwróćcie uwagę na to, że pyta ona o odwrotną rzecz niż to, co robi preventExtensions
).
Jeśli natomiast chcielibyśmy także uniemożliwić zmienianie deskryptorów własności oraz usuwanie własności, należy obiekt „zapieczętować” – służy do tego funkcja Object.seal(obj)
. Robi ona wszystko to, co preventExtensions
i trochę więcej: blokuje właśnie zmiany deskryptorów. Przykładowo:
var obj = { a: 5, b: 7 }; Object.seal(obj); obj.a = 31337; // zmiana wartości: zadziała delete obj.b; // usunięcie własności: silent failure; w strict: TypeError obj.c = 8; // dodanie własności: silent failure; w strict: TypeError
Również w tym przypadku zmiany te nie będą dotyczyć własności obecnych w prototypie naszego obiektu i wyżej w łańcuchu prototypów.
Funkcja Object.isSealed(obj)
zwróci informację o tym, czy obiekt jest zapieczętowany. Jej wynikiem będzie true
, jeśli na danym obiekcie wywołana została metoda Object.seal()
, a false
w przeciwnym przypadku.
Żeby całkowicie uniemożliwić manipulacje własnościami obiektu należy go zamrozić. Zamrożenie oznacza, że własności tego obiektu stają się własnościami tylko do odczytu, a obiekt staje się niemodyfikowalny. Służy do tego metoda Object.freeze(obj)
:
var obj = { a: 5, b: 7 }; Object.freeze(obj); obj.a = 31337; // zmiana wartości: silent failure; w strict: TypeError delete obj.b; // usunięcie własności: silent failure; w strict: TypeError obj.c = 8; // dodanie własności: silent failure; w strict: TypeError
Także i tutaj nie będą dotyczyć własności obecnych w prototypie naszego obiektu i wyżej w łańcuchu prototypów.
Funkcja Object.isFrozen(obj)
zwróci informację o tym, czy obiekt jest zamrożony. Jej wynikiem będzie true
, jeśli na danym obiekcie wywołana została metoda Object.freeze()
, a false
w przeciwnym przypadku.
Jeśli nasz obiekt zawiera referencje do innych obiektów (w tym tablic), to należy pamiętać, że w dalszym ciągu będzie można operować na tych obiektach:
var obj = { subArr: [1, 2, 3], subObj: { x: 5, y: 7 } }; Object.freeze(obj); alert(Object.isFrozen(obj)); // true alert(obj.subArr[1]); // "2" obj.subArr[1] = 5; alert(obj.subArr[1]); // "5" delete obj.subObj.x; alert(JSON.stringify(obj.subObj)); // '{"y":7}'
W powyższym przykładzie, gdyby zależało nam na niemodyfikowalności obiektów będących własnościami obiektu obj, należałoby wywołać freeze()
także na obj.subArr i obj.subObj.
Poniżej porównanie trzech opisanych wyżej funkcji w formie tabelki:
metoda Object.* \operacje |
zmiana wartości własności | (prze-)konfigurowanie własności | dodawanie nowych własności |
---|---|---|---|
(brak) | TAK | TAK | TAK |
preventExtensions() |
TAK | TAK | NIE |
seal() |
TAK | NIE | NIE |
freeze() |
NIE | NIE | NIE |
To tyle w tym odcinku. W kolejnym będziemy tworzyć nowe obiekty w łańcuchu prototypów, ale unikając operatora new
.
One thought on “Nowe podejście do obiektów w ECMAScript 5. Ograniczanie możliwości modyfikacji obiektów”