Объекты в JavaScript

Объект JavaScript и его свойства (поля)

Объект в JS — это набор свойств и их значений в памяти, на которые можно сослаться с помощью идентификатора.

Все объекты в JavaScript являются потомками Object; все объекты наследуют методы и свойства из прототипа объекта Object.prototype, хотя они и могут быть переопределены.

Свойство объекта – это пара «ключ: значение»:

  • ключ — это идентификатор (или имя) свойства (тип String или Symbol),
  • значения могут быть любыми (любой тип, включая другие объекты).

Свойства объекта также иногда называют полями объекта.

Т.к. значения свойств могут иметь любой тип (включая другие объекты), это позволяет строить сложные, разветвлённые иерархии данных.

Свойства, значениями которых являются функции, называются методами

После имени свойства следует двоеточие ":", и затем указывается значение свойства. Если в объекте несколько свойств, то они перечисляются через запятую.

Имя свойства должно соответствовать ограничениям, касающимся имён переменных JavaScript (например, должно содержать только буквы, цифры или символы $ и _), но может быть невалидным или состоять из нескольких слов, но тогда оно должно быть заключено в кавычки:

Последнее свойство объекта может заканчиваться запятой («висячая запятая»). Такой подход упрощает добавление, удаление и перемещение свойств, так как все строки объекта становятся одинаковыми.

Есть два типа свойств, отличающихся определенными атрибутами:

  1. свойство-значение (ассоциирует ключ со значением);
  2. свойство-акцессор (ассоциирует ключ с одной из двух функций-акцессоров: геттер и сеттер).

Особенности сравнения двух объектов

Два объекта не считаются равными, даже если они будут иметь одинаковые наборы свойств с одинаковыми значениями.

Два массива не считаются равными, даже если они имеют один и тот же набор элементов, следующих в том же порядке.

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

  • ВАЖНО! значения двух объектов считаются равными тогда и только тогда, когда они ссылаются на один и тот же объект в памяти.

Как следует из примера выше, операция присваивания объекта (или массива) переменной фактически присваивает ссылку: она не создает новую копию объекта. Если в программе потребуется создать новую копию объекта или массива, необходимо будет явно скопировать свойства объекта или элементы массива.

Читайте также JavaScript: Ядро

Виды объектов в JavaScript

Все объекты можно условно разделить на несколько видов:

  1. глобальный объект;
  2. объектные типы:
    • собственно объекты (коллекции свойств и их значений);
    • массивы (коллекции данных, упорядоченных в виде списка элементов);
    • функции (фрагменты программного кода (подпрограммы), позволяющие формализовать определённую логику поведения и обработки данных). 
  3. объекты-обертки.
Глобальный объект

Глобальный объект - это объект JavaScript, свойства которого являются глобальными идентификаторами, доступными из любого места программы на JavaScript.

Когда выполняется запуск интерпретатора JavaScript (или когда вебброузер загружает новую страницу), создается новый глобальный объект, в котором инициализируется начальный набор свойств, определяющих:

  1. глобальные свойства, такие как undefined, Infinity и NaN;
  2. глобальные функции, такие как isNaN(), parseInt() и eval();
  3. функции-конструкторы, такие как Date(), RegExp(), String(), Object() и Array();
  4. глобальные объекты, такие как Math и JS0N.

Имена первоначально устанавливаемых свойств глобального объекта можно отыскать по именам в справочном разделе по базовому JavaScript или в описании самого глобального объекта, под именем «Global».

В программном коде верхнего уровня, т. е. в JavaScript-коде, который не является частью функции, сослаться на глобальный объект можно посредством ключевого слова this :

В клиентском JavaScript имеется объект Window, определяющий другие глобальные свойства, описание которых можно найти в справочном разделе по клиентскому JavaScript. Этот глобальный объект имеет свойство window , ссылающееся на сам объект, которое можно использовать вместо ключевого слова this для ссылки на глобальный объект Window.

Объект Window определяет базовые глобальные свойства, а также дополнительные глобальные свойства, характерные для веб-броузеров и клиентского JavaScript. Однако этот специальный объект может также хранить глобальные переменные программы. Если программа объявляет глобальную переменную, она становится свойством глобального объекта.

[свернуть]

Создание объекта в JavaScript

В общем случае, в JavaScript новые объекты могут создаваться следующими способами:

  1. пустой объект:
    • с помощью фигурных скобок {…} с необязательным списком свойств (литеральная нотация);
    • методом Object.create(null);
  2. с помощью функции-"конструктора" объекта (через new Object(nameKlass), где nameKlass - функция-конструктор);
  3. клонировать существующий объект и расширить его:
    • делегированием через прототипы (объект ссылается или делегирует другому объекту):
      1. с помощью метода Object.create(nameKlass) (создание объекта из прототипа nameKlass);
      2. с использованием constructor;
    • конкатенацией объектов (объект формируется путем добавления новых свойств к объекту из других существующих объектов).

Особенности создания объектов различными способами

Особенности создания пустого объекта:

Создание объектов различными способами с передачей объекта в качестве аргумента:

[свернуть]
C помощью метода Object.create(nameKlass) (создание объекта из прототипа)

Метод Object.create() создаёт новый объект с указанными объектом прототипа и свойствами.

Параметры:

  • proto -  объект, который станет прототипом вновь созданного объекта;
  • propertiesObject -  (необязательный параметр) объект, чьи собственные перечисляемые свойства (то есть такие, которые определены на самом объекте, а не унаследованы по цепочке прототипов) указывают дескрипторы свойств, добавляемых в новый объект.

Метод Object.create() возвращает новый объект (не копию по ссылке) с заданным прототипом и свойствами.

[свернуть]

Обычно используют вариант с фигурными скобками {...}. Такое объявление называют литералом объекта (литеральной нотацией).

Литеральная инициализация объекта сразу задаёт определённое количество начальных свойств (полей), но в процессе работы приложения свойства (поля) объекта могут добавляться и (или) удаляться.

Таким образом, при использовании литерального синтаксиса {...} мы сразу можем:

  • сразу поместить в объект несколько свойств в виде пар «ключ: значение»;
  • создать пустой объект и добавить в него свойства позже.
Примеры

[свернуть]

Объект, объявленный через const, может быть изменён. Объявление const защищает от изменений только само именование объекта (в примере выше - nameObject), но не его свойства. 

В реальном коде часто необходимо использовать существующие переменные как значения для свойств с тем же именем.

Например:

В примере выше название свойств name и age совпадают с названиями переменных, которые мы подставляем в качестве значений этих свойств.  Вместо name:name мы можем написать просто name:

Замечание: Зарезервированные слова разрешено использовать как имена свойств (в отличие от имён переменных, которые не могут совпадать с зарезервированными словами, такими как «for», «let», «return» и т.д.)

Работа со свойствами объекта в JavaScript

Обращение к свойствам объекта в JS:

Для обращения к свойствам объекта в JavaScript используется два варианта записи:

1. Запись "через точку"

[свернуть]
2. Запись "через квадратные скобки"

[свернуть]

Кроме того, квадратные скобки ( [] ) в коде объектов также используются:

  • для обращения к свойству, имя которого является результатом выражения;
  • для ключей, заданных в кавычках (невалидных);
  • для обращения к вычисляемому свойству.

Помните! В JavaScript к свойствам, начинающимся с цифры, невозможно обратиться посредством точечной нотации; к ним можно обратиться только с помощью скобочной нотации.

Примеры

Квадратные скобки в литеральной нотации могут использоваться для создания вычисляемого свойства.

Пример:

Смысл вычисляемого свойства прост: запись [fruit] означает, что имя свойства необходимо взять из переменной fruit.

И если посетитель введёт слово "apple", то в объекте bag теперь будет лежать свойство {apple: 5}.

Мы можем использовать и более сложные выражения в квадратных скобках:

В большинстве случаев, когда имена свойств известны и просты, используется запись через точку. Если же нам нужно что-то более сложное, то мы используем квадратные скобки.

[свернуть]
Добавление или удаление свойства объекта в JS

Удаление свойства объекта JS оператором delete:

где результат вычисления выражения должен быть ссылкой на свойство (объекта), например:

Если результат вычисления выражения не является свойством (объекта), delete ничего не делает. Ещё пример:

[свернуть]
Проверка существования свойства объекта JS

Особенность объектов в том, что можно получить доступ к любому свойству. Даже если свойства не существует – ошибки не будет!

При обращении к свойству, которого нет, возвращается undefined.

Способы проверки существования свойства объекта JavaScript:

  1. сравнением его с undefined;
  2. с помощью оператора "in".

Функция проверки объекта на пустоту

Замечание по строгому сравнению "=== undefined"

Если свойство существует, но содержит значение undefined, то строгого сравнения "=== undefined" не достаточно для проверки наличия свойства:

Подобные ситуации случаются очень редко, так как undefined обычно явно не присваивается. Для «неизвестных» или «пустых» свойств мы используем значение null. Таким образом, оператор in является экзотическим гостем в коде.

[свернуть]

Перебор свoйств oбъекта JavaScript циклoм «for…in»

Для перебора всех свойств объекта используется цикл for..in.

[свернуть]

Получение массива, содержащего перечисляемые свойства объекта ( метод Object.keys() )

Метод Object.keys() возвращает массив из собственных перечисляемых свойств переданного объекта в том же порядке, в котором они бы обходились циклом for...in.

Отличие for...in от Object.keys():

  • цикл for...in перечисляет свойства и из цепочки прототипов.

где obj - объект, чьи собственные перечисляемые свойства будут возвращены.

Метод Object.keys возвращает массив строковых элементов, соответствующих именам перечисляемых свойств, найденных непосредственно в самом объекте. Порядок свойств такой же, как и при ручном перечислении свойств в объекте через цикл.

Например (отсюда):

Подробнее о перечисляемых и не перечисляемых свойствах.

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

[свернуть]

Получение массива перечисляемых свойств объекта в формате key, value (метод Object.entries() )

Метод Object.entries() возвращает массив собственных перечисляемых свойств указанного объекта в формате [key, value], в том же порядке, что и в цикле for...in (разница в том, что for-in также перечисляет свойства из цепочки прототипов).

Порядок элементов в массиве который возвращается Object.entries() не зависит от того как объект объявлен. Если существует необходимость вывести в определенном порядке, то массив должен быть отсортирован до вызова метода, например Object.entries(obj).sort((a, b) => a[0] - b[0]);.

где obj - объект, чьи перечислимые свойства будут возвращены в виде массива [key, value].

Метод возвращает массив перечислений собственных свойств объекта с парами [key, value]. Порядок свойств тот же, что и при прохождении циклом по свойствам объекта вручную.

Примеры: 

[свернуть]

Получение массива имен (в т.ч. Symbol) полей объекта (метод Reflect.ownKeys() )

Статический метод Reflect.ownKeys() возвращает массив имён, а также Symbol собственных полей объекта.

Синтаксис:

Reflect.ownKeys(target)

где target - объект, из которого получаем собственные ключи.

Возвращаемое значение:

  • массив собственных полей объекта target.

Reflect.ownKeys(target) выбрасывает исключение TypeError, если target не является Object.

Метод Reflect.ownKeys() является эквивалентом метода Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)).

Пример:

[свернуть]
Преобразование списка пар key: value в объект (метод Object.fromEntries() )

Метод Object.fromEntries() преобразует список пар ключ-значение в объект.

где iterable - итерируемый объект (такой как Array или Map или другие объекты, реализующие протокол итерации).

Метод Object.fromEntries() принимает список пар ключ-значение и возвращает новый объект, свойства которого задаются этими записями. Ожидается, что аргумент iterable будет объектом, который реализует метод @@iterator. Итератор создает двуэлементный массивоподобный объект, первый элемент которого является значением, используемым в качестве ключа свойства, а второй элемент — значением свойства, связанного с этим ключом.

Object.fromEntries() выполняет процедуру, обратную Object.entries().

[свернуть]
Упорядочение (сортировка) свойств объекта

Свойства объекта упорядочены особым образом:

  • свойства с целочисленными ключами сортируются по возрастанию, остальные располагаются в порядке создания.

Термин «целочисленное свойство» означает строку, которая может быть преобразована в целое число и обратно без изменений (например, свойства 5, 7, 24, 69 и т.п. - целочисленные, а свойства "+49" или "1.2" целочисленными не являются).

Пример:

Пример сортировки целочисленных свойств:

Для изменения сортировки необходимо сделать свойства не целочисленными (например, добавив "+"):

[свернуть]

Копирование объектов в JS (по ссылке)

Примитивные типы: строки, числа, логические значения – присваиваются и копируются «по значению», например:

В результате мы имеем две независимые переменные, каждая из которых хранит строку "Hello!".

Объекты ведут себя иначе. Одним из фундаментальных отличий объектов от примитивных типов данных является то, что они хранятся и копируются «по ссылке».

Переменная хранит не сам объект, а его «адрес в памяти», другими словами «ссылку» на него. Когда переменная объекта копируется – копируется ссылка, сам же объект не дублируется.

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

Сравнение объектов в JS

Операторы равенства == и строгого равенства === для объектов работают одинаково.

Два объекта равны только в том случае, если это один и тот же объект.

Например, если было выполнено копирование (по ссылке) , т.е. две переменные ссылаются на один и тот же объект, то они равны:

Не будут равны объекты хотя и пустые, но независимые:

Объекты преобразуются в примитивы при сравнении:

  • типа obj1 > obj2 или 
  • с примитивом obj == 5 .

Дублирование и объединение объектов. Метод  Object.assign и оператор spread

Поверхностное клонирование (дублирование) объектов JS оператором for

Поверхностная копия скопирует только свойства верхнего уровня, вложенные объекты будут скопированы "по ссылке" и могут использоваться как оригиналом, так и копией.

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

Поверхностное клонирование (дублирование) объектов JS методом Object.assign

Используется для дублирования и объединения объектов в JS.

Аргументы dest, и src1, ..., srcN являются объектами. Метод копирует свойства всех объектов src1, ..., srcN в объект dest. То есть, свойства всех перечисленных объектов, начиная со второго, последовательно копируются в первый объект.

Если принимающий объект (dest) уже имеет свойство с таким именем, оно будет перезаписано.

После копирования метод возвращает объект dest.

Использование Object.assign для простого клонирования (дублирования):

Все свойства объекта user будут скопированы в пустой объект, и ссылка на этот объект будет в переменной clone

Устранение undefined при доступе к несуществующему свойству объекта

Отсюда

Чтобы избежать появления значения undefined при доступе к несуществующему свойству объекта необходимо:

  1. определить объект defaults, который содержит значения свойств по умолчанию;
  2. вызвать функцию Object.assign({ }, defaults), чтобы создать новый объект.

Например, новый объект options получает все свойства из unsafeOptions, недостающие берутся из defaults:

unsafeOptions содержит только свойство fontSize. Объект defaults указывает значения по умолчанию для fontSize и color. Object.assign() принимает первый аргумент как целевой объект {}. Целевой объект получает значение свойства fontSize из объекта-источника unsafeOptions. А значение свойства color — из объекта-источника defaults, поскольку unsafeOptions не содержит color.

Важен порядок, в котором перечислены исходные объекты: первый пришёл – первый ушёл.

Теперь возможно получить доступ к любому свойству объекта options, включая options.color, который изначально был недоступен в unsafeOptions.

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

[свернуть]

Поверхностное клонирование (дублирование) объектов JS оператором spread (spread syntax)

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

Вместо вызова Object.assign() используйте spread syntax - синтаксис распространения объекта ( ... ), чтобы скопировать в целевой объект все собственные и перечисляемые свойства из исходных объектов:

Инициализатор объекта распространяет свойства из исходных объектов defaults и unsafeOptions.

Важен порядок, в котором указаны исходные объекты: свойства более позднего исходного объекта перезаписывают более ранние.

Обратите внимание, что Object.assign() запускает setters, а spread syntax нет.

Примеры

Обратите внимание, что вы не можете заменить или имитировать функцию Object.assign():

В приведенном выше примере оператор распространения не работает так, как можно было бы ожидать: он распространяет массив аргументов в литерал объекта благодаря параметру rest.

[свернуть]

Глубокое клонирование (дублирование) сложных объектов (содержащих вложенные объекты)

Глубокая копия продублирует каждый объект на пути клонирования. Оригинал и клонированный объект не будут иметь ничего общего (будут являться разными объектами).

Пусть есть объект user, содержащий вложенный объект  "user-adress":

В процессе клонирования родительского объекта недостаточно просто скопировать вложенный объект "user-adress": он будет скопирован по ссылке, а значит объекты clone и user в своих свойствах "user-adress" будут ссылаться на один и тот же объект.

Чтобы исправить это положение, мы должны в цикле клонирования делать проверку не является ли значение user[key] объектом, и если это так – копировать и его структуру тоже. Это называется «глубокое клонирование».

Существует стандартный алгоритм глубокого клонирования, Structured cloning algorithm. Он решает описанную выше задачу, а также более сложные задачи. Мы можем использовать реализацию этого алгоритма из JavaScript-библиотеки lodash, метод _.cloneDeep(obj).

Глубокое клонирование объектов через JSON

Глубокое клонирование объектов 

ВАЖНО! Этот метод нельзя использовать для копирования методов (т.е. функций) объекта, которые были написаны пользователем. Методы объекта копируются с помощью метода Object.assign.

Пример

[свернуть]

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.