В этом посте мы рассмотрим, как создаются объекты, затем поговорим о некоторых интересных свойствах свойств объекта, но сначала давайте начнем с рассмотрения того, как мы обычно создаем объекты, используя литералы объектов:
const car = { numberplate: '1234' };
Мы создали объект, содержащий свойство numberplate
со значением '1234'
. За кулисами javascript использует метод Object.create
для создания этого объекта. Вот как это выглядит:
const car = Object.create(
Object.prototype,
{
numberplate: {
writable: true,
enumerable: true,
configurable: true,
value: '1234',
}
},
);
Два приведенных выше фрагмента кода абсолютно эквивалентны, и вы можете понять, почему мы используем литералы объектов, но давайте уделим немного времени тому, чтобы понять, что происходит во втором фрагменте.
В качестве первого аргумента Object.create
принимает объект, который должен быть прототип вновь созданного объекта, поскольку у нас нет или не требуется какого-либо прототипного наследования, мы указываем, что он должен принимать прототип объекта по умолчанию.
Что еще интереснее, второй аргумент указывает дескрипторы свойств, которые будут добавлены к вновь созданный объект с соответствующими именами свойств.
Обратите внимание, что вы также можете использовать
Object.defineProperties
илиObject.defineProperty
для указания дескрипторов свойств для любого заданного объекта. Подробнее об этом здесь и здесь.
Давайте посмотрим, за что отвечает каждый дескриптор свойства.
Дескрипторы свойств
Доступно для записи
Дескриптор свойства writable
определяет, может ли значение свойства (в данном случае numberplate
) быть изменено по сравнению с его начальным значением.
'use strict'
const car = { numberplate: '1234' };
Object.defineProperty( car, 'numberplate', { writable: false } );
car.numberplate = '0000'; // -> Uncaught TypeError
Обратите внимание, что если вы не используете строгий режим (с
'use strict'
) в приведенном выше примере, интерпретатор не выдаст ошибку, и значение не будет изменено.
Есть предостережение, о котором следует знать. Дескриптор свойства writable
останавливает перемещение указателя свойства. это означает, что если свойство указывает на объект, члены этого объекта все еще могут быть изменены, например:
'use strict'
const plane = { numberplate: { value: '1234' }, };
Object.defineProperty( plane, 'numberplate', { writable: false } );
plane.numberplate.value = '0000';
plane.numberplate.value // -> '0000'
plane.numberplate = {}; // -> Uncaught TypeError
Исчисляемый
По умолчанию свойства объекта являются перечисляемыми, поэтому мы можем перечислить их с помощью циклов for...in
и получить их в виде массива с помощью Object.keys
.
Обратите внимание, что разница между этими двумя способами получения перечислимых свойств заключается в том, что
Object.keys
возвращает только массив с собственными свойствами объекта, а циклfor...in
возвращает также ключи, найденные в цепочке прототипов.
const car = { numberplate: '1234', brand: 'Koenigsegg', };
Object.defineProperty( car, 'numberplate', { enumerable: false } );
Object.keys(car); // -> [brand]
Установка для enumerable
значения false
также повлияет на JSON
сериализацию свойства, поскольку оно не будет сериализовано. Это может быть полезно в некоторых случаях.
Настраиваемый
Дескриптор свойства configurable
предотвращает изменение дескрипторов (данного свойства, например: platenumber
). Кроме того, это предотвращает удаление свойства из объекта. Давайте посмотрим пример:
'use strict'
const car = { numberplate: '1234', };
Object.defineProperty( car, 'numberplate', { configurable: false } );
delete car.numberplate; // -> Uncaught TypeError
Object.defineProperty( car, 'numberplate', { enumerable: false } ); // -> Uncaught TypeError
Object.defineProperty( car, 'numberplate', { configurable: true } ); // -> Uncaught TypeError
После того как вы установите настраиваемый дескриптор свойства на
false
, вы не сможете позже переключить его обратно наtrue
.
Одно предостережение, о котором следует помнить, заключается в том, что даже если вы установитеconfigurable
наfalse
, вы все равно можете изменить дескрипторwritable
.
Ценить
Наконец, дескриптор значения предназначен для установки или изменения значения свойства.
'use strict'
const car = { numberplate: '1234', };
Object.defineProperty( car, 'numberplate', { value: '0000' } );
car.numberplate; // -> '0000'
Сеттер и геттер
Добытчики
Еще одна полезная вещь, которую вы могли бы сделать с Object.create
(или Object.defineProperty
, или Object.defineProperties
), — это реализация сеттеров и геттеров. Давайте посмотрим, как мы можем это сделать.
const point = { x: 0, y: 0 };
Object.defineProperty( point, 'position', { get: function() { return [this.x, this.y]; } } );
point.position; // -> [0, 0]
Чтобы создать геттер, вы устанавливаете атрибут get
в функцию, эта функция и есть наш геттер.
Сеттеры
const point = { x: 0, y: 0 };
Object.defineProperty(
point,
'position',
{
set: function(pointArray) {
[this.x, this.y] = pointArray;
}
}
);
point.position = [4, 2];
point.x; // -> 4
point.y; // -> 2
Как и для геттера, для реализации сеттера мы устанавливаем атрибут set
для функции, которая принимает аргумент, аргумент — это значение, которое вы хотите установить.
Обратите внимание, что когда вы устанавливаете геттер или сеттер для свойства, у него не может быть дескриптора свойства с возможностью записи или значения. См. ниже:
Object.getOwnPropertyDescriptor(
point,
'position'
); // -> { enumerable: false,
// configurable: false,
// get: ƒ, set: ƒ }
Обратите внимание, что при установке геттера или сеттера дескрипторам
enumerable
иconfigurable
автоматически присваивается значениеfalse
. Таким образом, вы можете установить геттеры и сеттеры в одном и том же выражении или вручную установитьconfigurable
вtrue
при их реализации.
шляпа это для этого поста. Надеюсь, вам понравилось. Если да, поделитесь, пожалуйста, с друзьями и коллегами. Кроме того, вы можете следить за мной в Твиттере по адресу @theAngularGuy, так как это очень поможет мне.
На следующей неделе мы поговорим о классах ES6 и о том, как они сравниваются с функциями-конструкторами, так что обязательно оставайтесь с нами.
Хорошего дня!