По умолчанию все 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-библиотеками состоит в том, что разработчики случайно (или намеренно) изменяют главный объект библиотеки. Замораживание (или запечатывание) главного объекта библиотеки помогает предотвратить некоторые из таких ошибок.