Константные объекты. Запрет изменения объекта

Последнее обновление: 25.10.2023

Язык JavaScript позволяет нам динамически менять свойства объектов, добавлять в объекты новые свойства и методы или удалять уже имеющиеся. Однако, подобные изменения объекта могут быть нежелательны. И JavaScript предоставляет для этого три механизма:

  • Запрет расширения объектов

  • Закрытие (sealing) объектов

  • Заморозка (freezing) объектов

Запрет расширения объектов

Метод Object.preventExtensions() позволяет запретить расширение объекта, то есть в этот объект нельзя добавлять новые свойства и методы. Метод Object.preventExtensions() в качестве параметра принимает целевой объект, для которого надо установить запрет на расширение.

Сначала возьмем пример, где мы успешно добавляем новое свойство:

const tom = {name: "Tom"};
// добавляем в объект tom новое свойство - company
tom.company = "Localhost";

console.log(`Name: ${tom.name}  Company: ${tom.company}`); // Name: Tom  Company: Localhost

Здесь в объект tom добавляется новое свойство company. После добавления мы можем использовать это свойство.

Теперь запретим расширение, применив метод Object.preventExtensions():

const tom = {name: "Tom"};
Object.preventExtensions(tom);	// запрещаем расширение объекта tom
tom.company = "Localhost";	// пытаемся добавить в объект tom новое свойство
console.log(`Name: ${tom.name}  Company: ${tom.company}`); // Name: Tom  Company: undefined

В итоге даже если мы попытаемся определить для объекта новое свойство, оно не будет добавлено. А при попытке обратиться к подобному свойству мы получим undefined

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

const tom = {name: "Tom"};
console.log(Object.isExtensible(tom));	// true
Object.preventExtensions(tom);	// запрещаем расширение объекта tom
console.log(Object.isExtensible(tom));	// false

Закрытие объектов

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

Сначала посмотрим, что мы можем сделать с объектом без применения Object.seal():

const tom = {name: "Tom"};

// для свойства name запрещаем изменение
Object.defineProperty(tom, "name", { writable: false});
tom.name = "Tomas";

// добавляем новое свойство - age
tom.age = 39;
console.log(`Name: ${tom.name}  Age: ${tom.age}`);	// Name: Tom  Age: 39

// для свойства name разрешаем изменение
Object.defineProperty(tom, "name", { writable: true});
tom.name = "Tomas";
console.log(`Name: ${tom.name}  Age: ${tom.age}`);	// Name: Tomas  Age: 39

Итак, мы можем изменить конфигурацию свойства (здесь делаем свойство name недоступным для записи). И также мы можем добавить в объект новое свойство.

Теперь применим метод Object.seal():

const tom = {name: "Tom"};
Object.seal(tom);		// закрываем объект tom от расширения и изменения конфигурации
// для свойства name запрещаем изменение
Object.defineProperty(tom, "name", { writable: false});
tom.name = "Tomas";

// добавляем новое свойство - age
tom.age = 39;
console.log(`Name: ${tom.name}  Age: ${tom.age}`);	// Name: Tom  Age: undefined

// для свойства name разрешаем изменение
Object.defineProperty(tom, "name", { writable: true}); // Uncaught TypeError: Cannot redefine property: name

После закрытия объекта методом Object.seal(tom) мы не сможем добавить в объект новое свойство. Соответственно в примере выше свойство tom.age будет равно undefined. И также мы не сможем повторно изменить конфигурацию свойства. Так, здесь при втором вызове метода Object.defineProperty() для свойства name мы столкнемся с ошибкой "Uncaught TypeError: Cannot redefine property: name".

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

const tom = {name: "Tom"};
console.log(Object.isExtensible(tom));	// true
console.log(Object.isSealed(tom));		// false
Object.seal(tom);		// закрываем объект tom
console.log(Object.isExtensible(tom));	// false
console.log(Object.isSealed(tom));		// true

Запрет на изменение значений свойств

Заморозка или freezing позволяет запретить изменение значений свойств, то есть позволяет сделать объект в полной мере константным. Так, просто определить объект как обычную константу с помощью оператора const недостаточно. Например:

const tom = {name: "Tom"};
tom.name= "Tomas";
console.log(tom.name);	// Tomas

Здесь мы видим, что свойство объекта изменило свое значение, хотя объект определен как константа.

Оператор const лишь влияет на то, что мы не можем присвоить константе новое значение, например, как в следующем случае:

const tom = {name: "Tom"};
tom = {name: "Sam"};	// Ошибка - нельзя константе присвоить значение второй раз

Тем не менее значения свойств объекта мы можем изменять.

Чтобы сделать объект действительно константным, необходимо применить специальный метод Object.freeze(). В этот метод в качестве параметра передается объект, который надо сделать константным:

const tom = {name: "Tom"};
Object.freeze(tom);
tom.name= "Tomas";		// значение свойства нельзя изменить
console.log(tom.name);	// Tom

Для проверки, можно ли изменить значения свойств объекта, применяется метод Object.isFrozen() - если значения свойств изменить нельзя, он возвращает true

Следует отметить, что "замороженный" объект - это крайняя степень запрета изменений на объекте. Соответственно такой объект нерасширяем, и также нельзя изменить конфигурацию его свойств:

const tom = {name: "Tom"};
console.log(Object.isExtensible(tom));	// true
console.log(Object.isSealed(tom));		// false
console.log(Object.isFrozen(tom));		// false
Object.freeze(tom);
console.log(Object.isExtensible(tom));	// false
console.log(Object.isSealed(tom));		// true
console.log(Object.isFrozen(tom));		// true
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850