Еще один способ создания объекта предоставляет функция Object.create, которая принимает два параметра. Первый параметр - прототип, на основе которого будет создаваться объект, а второй параметр - определение свойств и методов объекта:
const tom = Object.create(прототип, { свойства и методы });
Например:
const tom = Object.create(Object.prototype, { name: { value: "Tom" }, age: { value: 39 }, print: { value: function() { console.log(`Name: ${this.name} Age: ${this.age}`); } }}); console.log(tom.name); // Tom console.log(tom.age); // 39 tom.print(); // Name: Tom Age: 39
Здесь в качестве прототипа в функцию Object.create()
передается прототип Object - Object.prototype
. Второй параметр функции -
определение свойств вида:
имя_свойства/метода: { value: значение_свойства/метода }
Имени свойства/метода сопоставляется объект, в котором есть свойство value - это свойство собственно и хранит значение свойства/метода. Например, свойство age равно 39:
age: { value: 39 }
Для метода значением выступает определение функции.
После создания объекта мы можем обращаться к его свойствам и методам, как и в общем случае:
console.log(tom.age); // 39
Подобный способ создания объектов может показаться чересчур громоздким и избыточным. Тем не менее он позволяет чуть детальнее настроить конфигурацию свойств. Так, кроме поля value при конфигурации свойства мы можем задать дополнительные поля:
writeable: хранит логическое значение, которое указывает, доступно ли это свойство для записи, то есть можно ли ему присвоить новое значение. По умолчанию этот атрибут имеет значение false.
enumerable: хранит логическое значение, которое указывает, является ли соответствующее свойство перечислимым, то есть включается ли это свойство при переборе свойств соответствующего объекта (например, с использованием цикла for...in). По умолчанию имеет значение false.
configurable: хранит логическое значение, которое указывает, можно ли изменить сам атрибут для соответствующего свойства, то есть можно ли впоследствии настроить свойство с помощью атрибутов. Значение по умолчанию для этого атрибута также равно false
set: определяет, какая функция вызывается при изменении значения свойства
get: определяет, какая функция вызывается при чтении значения свойства
Применим некоторые из этих атрибутов:
const tom = Object.create(Object.prototype, { name: { value: "Tom", enumerable: true, // доступно для перебора writable: false // НЕ доступно для записи }, age: { value: 39, enumerable: true, // доступно для перебора writable: true // доступно для записи }, print: { value: function() { console.log(`Name: ${this.name} Age: ${this.age}`);}, enumerable: false, // не доступно для перебора writable: false, // НЕ доступно для записи } }); console.log(tom.name); // Tom tom.name = "Tomas"; console.log(tom.name); // Tom - свойство name не доступно для изменения console.log(tom.age); // 39 tom.age = 22; console.log(tom.age); // 22 - свойство age доступно для изменения tom.print(); // Name: Tom Age: 22 // перебор объекта for(prop in tom){ console.log(prop); } // Консольный вывод: // name // age
В примере выше функция Object.create
использует много кода для создания объекта. Но что, если у нас есть куча свойств и методов, но некоторая конфигурация (например, сделать
свойство доступно только для чтения) нужна только для одного свойства? В этом случае мы можем создать объект стандартным образом, а все дополнительные свойства, которые требуют конфигурации,
определить с помощью функции Object.defineProperty:
const tom = { age:39, print: function() { console.log(`Name: ${this.name} Age: ${this.age}`);} }; Object.defineProperty(tom, "name", { value: "Tom", writable: false // НЕ доступно для записи }); console.log(tom.name); // Tom tom.name = "Tomas"; console.log(tom.name); // Tom - свойство name не доступно для изменения tom.print(); // Name: Tom Age: 22
Функция Object.defineProperty() принимает три параметра. Первый параметр - объект, для которого определяется свойство. Второй параметр - название свойства. Третий параметр - конфигурационный объект. То есть в данном случае доопределяем для объекта tom свойство name, которое будет достпуно только для чтения.
Если надо подобным образом доопределить несколько свойств, то применяется функция Object.defineProperties, которая принимает объект и набор конфигурационных настроек для добавляемых свойств:
const tom = { age:39 }; // доопределяем свойства для объекта tom Object.defineProperties(tom, { name: { // определяем свойство name value: "Tom", writable: false // НЕ доступно для записи }, print: { // определяем метод print value: function() { console.log(`Name: ${this.name} Age: ${this.age}`);}, writable: false, // НЕ доступно для записи } }); tom.name = "Tomas"; // свойство name не доступно для изменения tom.print = function(){console.log("Hello Word");} // метод print не доступен для изменения tom.print(); // Name: Tom Age: 39
Стоит отметить, что подобным образом мы можем не только добавлять новые свойства, но и переопределять конфигурацию уже существующих свойств. Например:
const tom = {name: "Tom"}; // для свойства name запрещаем изменение Object.defineProperty(tom, "name", { writable: false}); tom.name = "Tomas"; console.log(tom.name); // Tom - значение свойства не изменилось