Всё о нерасширяемых объектах

всё о нерасширяемых объектах в javascript

По умолчанию все JavaScript-объекты являются расширяемыми (extensible), то есть вы можете в любое время добавлять к объекту свойства и методы. Например, можно определить объект и позднее добавить в него другое свойство:

var person = {name: "Nicholas"};
person.age = 29;

Хотя объект person полностью определен в первой строке, во второй строке мы добавляем к нему еще одно свойство. С помощью метода Object.preventExtensions()можно запретить добавление к объекту новых свойств и методов, например:

var person = {name: "Nicholas"};
Object.preventExtensions(person);

person.age = 29;
alert(person.age); // undefined

После вызова метода Object.preventExtensions() добавлять новые свойства или методы к объекту person будет нельзя. В нестрогом режиме попытка добавить новый член к объекту просто игнорируется, поэтому свойство person.age имеет значение undefined. В строгом режиме попытка добавить новый член к объекту, расширить который запрещено, вызывает ошибку.

Даже если к объекту нельзя добавить новые члены, все имеющиеся у него члены остаются без изменений, и вы можете изменять и удалять их. С помощью методаObject.isExtensible() можно узнать разрешено ли расширение объекта:

var person = {name: "Nicholas"};
alert(Object.isExtensible(person)); // true

Object.preventExtensions(person);
alert(Object.isExtensible(person)); // false

Примечание

В ES5, если аргумент метода не является объектом (является примитивным значением), будет выброшено исключение TypeError. В ES6 такой аргумент будет рассматриваться, как простой не- расширяемый объект и метод его просто вернёт.

Object.preventExtensions(1)
TypeError: 1 is not an object // код ES5
Object.preventExtensions(1)
1                             // код ES6

Запечатанные объекты

Следующий уровень защиты объектов в ECMAScript 5 — запечатанные объекты (sealed objects). Запечатанные объекты нельзя расширять, а у членов, которые у них уже есть атрибут [[Configurable]] имеет значение false. Это означает, что свойства и методы нельзя удалять, а свойства с данными с помощью метода Object.definePropery() нельзя заменять свойствами с функциями доступа, и наоборот.

Запечатать объект можно с помощью метода Object.seal():

var person = {name: "Nicholas"};
Object.seal(person);

person.age = 29;
alert(person.age); // undefined

delete person.name;
alert(person.name); // "Nicholas"

В этом примере попытка добавить свойство age игнорируется. Попытка удалить свойство name также игнорируется, так что значение остается без изменений. Так код работает в нестрогом режиме. В строгом режиме попытка добавить или удалить член запечатанного объекта приводит к ошибке.

Узнать, запечатан ли объект можно с помощью метода Object.isSealed(). Поскольку запечатанный объект расширять нельзя, метод Object.isExtensible() для него возвращает false.

var person = {name: "Nicholas"};
alert(Object.isExtensible(person)); // true
alert(Object.isSealed(person)); // false

Object.seal(person);
alert(Object.isExtensible(person)); // false
alert(Object.isSealed(person)); // true

Примечание

В ES5, если аргумент метода не является объектом (является примитивным значением), будет выброшено исключение TypeError. В ES6 такой аргумент будет рассматриваться, как простой не расширяемый объект и метод его просто вернёт.

Object.preventExtensions(1)
TypeError: 1 is not an object // код ES5

Object.preventExtensions(1)
1                             // код ES6

Замороженные объекты

Самый надёжный уровень защиты от изменений — замороженные объекты (frozen objects). Их нельзя расширять, они запечатаны, а у их свойств с данными атрибут [[Writable]] имеет значение false. Свойства с функциями доступа доступны для записи, но только если определена функция [[Set]]. В ECMAScript 5 для замораживания объектов используется метод Object.freeze():

var person = {name: "Nicholas"};
Object.freeze(person);

person.age = 29;
alert(person.age); // undefined

delete person.name;
alert(person.name); // "Nicholas"

person.name = "Greg";
alert(person.name); // "Nicholas"

Как в случае нерасширяемых и запечатанных объектов, попытка выполнить запрещенные операции для замороженного объекта в нестрогом режиме игнорируется, а в строгом приводит к ошибке.

Для распознавания замороженных объектов хорошо подходит метод Object.isFrozen(). Поскольку замороженные объекты являются запечатанными и расширяемыми, метод Object.isExtensible() для них возвращает false, а метод Object.isSealed() — true:

var person = {name: "Nicholas"};
alert(Object.isExtensible(person)); // true
alert(Object.isSealed(person)); // false
alert(Object.isFrozen(person)); // false

Object.isFrozen(person);
alert(Object.isExtensible(person)); // false
alert(Object.isSealed(person)); // true
alert(Object.isFrozen(person)); // true

Примечание

В ES5, если аргумент метода не является объектом (является примитивным значением), будет выброшено исключение TypeError. В ES2015 такой аргумент будет рассматриваться, как простой замороженный объект и метод его просто вернёт.

Object.freeze(1)
TypeError: 1 is not an object // код ES5

Object.freeze(1)
1                             // код ES2015

Замороженные объекты особенно полезны при разработке библиотек. Одна из частых проблем с JavaScript-библиотеками состоит в том, что разработчики случайно (или намеренно) изменяют главный объект библиотеки. Замораживание (или запечатывание) главного объекта библиотеки помогает предотвратить некоторые из таких ошибок.