Введение в мутацию объектов в JavaScript

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

В этой статье представлен обзор мутации объектов в JavaScript с соответствующими примерами кода по необходимости.

Типы данных в JavaScript

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

Примитивные типы данных

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

Определенные пользователем или ссылочные типы данных

Определенные пользователем типы данных или ссылочные типы данных – это объекты, созданные с использованием примитивных типов или комбинации примитивных и определенных пользователем типов. Типичными примерами определенных пользователем или ссылочных типов являются объекты и массивы.

Присвоение и повторное присвоение переменных в JavaScript

Когда вы присваиваете переменной примитивного типа значение другой переменной примитивного типа variable, обе переменные содержат схожие значения, но хранятся в разных местах памяти. Например, предположим, что у вас есть две переменные varA и varB, и вы присваиваете одну переменную другой следующим образом:

JavaScript

 

Когда вы выполняете приведенный выше код, число 100 будет отображено на консоли. Теперь вы изменяете значения одной из двух переменных (например, varB) следующим образом.

JavaScript

 

Обратите внимание, как значение переменной varB изменилось на 500. Когда вы печатаете значение varA, оно по-прежнему будет равно 100. Это происходит потому, что переменные varA и varB хранятся в двух разных ячейках памяти. Таким образом, если вы измените одну из них, новое или измененное значение не отразится на других переменных.

Что такое мутация объектов в JavaScript?

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

Мутации объектов могут создавать несколько проблем, таких как следующие:

  • Измененные объекты могут часто приводить к гонкам из-за проблем с параллелизмом и безопасностью потоков.
  • Мутация может привести к сложностям в исходном коде из-за проблем предсказуемости и безопасности потоков
  • Мутация часто может привести к ошибкам, которые могут быть сложными для идентификации в исходном коде приложения
  • Мутация делает тестирование и отладку кода сложными, потому что отслеживание кода, использующего мутацию, становится вызовом

Примеры кода, демонстрирующие мутацию объектов

Мутация объектов может происходить в любом из следующих сценариев:

  • Добавление, изменение или удаление свойств
  • Использование методов, способных проявлять мутацию

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

JavaScript

 

В предыдущем фрагменте кода мы создаем объект с именем автор, содержащий два свойства, а именно, id и name. В то время как свойство id используется для хранения id записи автора, свойство name хранит имя автора. Обратите внимание, как мы изменяем объект автора, изменив значение, относящееся к свойству id. Затем мы добавляем новое свойство с именем city в объект автора и присваиваем ему значение.

При запуске предыдущего фрагмента кода свойства и их значения объекта автора будут отображены как показано ниже:

JavaScript

 

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

Рассмотрим следующий фрагмент кода, показывающий, как можно создать объект в JavaScript, а затем присвоить его переменной.

JavaScript

 

В предыдущем фрагменте кода объект objA присваивается переменной objB, и значение свойства pincode объекта objA изменяется, т.е. объект objA мутируется. При выполнении программы будет отображены следующие данные.

JavaScript

 

Обратите внимание, что значение свойства pincode было изменено.

Предотвращение мутации объектов в JavaScript

В JavaScript можно предотвратить мутацию несколькими способами, включая следующие: 

  • Использование клонирования объекта с помощью метода Object.assign() или оператора spread (…)
  • Использование метода Object.seal() для предотвращения добавления или удаления свойств объекта
  • Использование метода Object.freeze() для предотвращения добавления, редактирования или удаления свойств объекта

Использование клонирования

Обратитесь к следующему фрагменту кода, показывающему, как можно клонировать объект в JavaScript с использованием оператора spread.

JavaScript

 

Здесь имя клонированного объекта clonedObj, и он идентичен оригинальному объекту с именем originalObj. Таким образом, если вы отобразите значения двух свойств этих двух объектов, результаты будут одинаковыми.

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

Plain Text

 

Теперь напишите следующий фрагмент кода для отображения значения свойства с именем x, относящегося к двум объектам originalObj и clonedObj.

Plain Text

 

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

Plain Text

 

Использование метода Object.freeze()

Метод Object.freeze() может сделать объект неизменным, предотвращая любые изменения его свойств.

JavaScript

 

Когда вы выполните предыдущий фрагмент кода, результаты будут аналогичны следующему:

JavaScript

 

Как видно из вывода, даже если вы присвоили значения свойствам city и state, и pincode, никаких изменений не произошло. Таким образом, данные, содержащиеся в любом из свойств объекта, остаются неизменными.

Использование метода Object.seal()

Вы также можете использовать метод Object.seal() для предотвращения мутации объектов в JavaScript. Этот метод позволяет изменять значения существующих свойств, но вы не можете модифицировать или удалять любые свойства объекта. Приведенный ниже пример кода иллюстрирует это:

JavaScript

 

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

JavaScript

 

Использование метода Object.defineProperty()

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

JavaScript

 

Когда вы выполните предыдущий фрагмент кода, вы увидите, что на консоли отображается число 3.

Основные моменты

  • JavaScript категоризирует типы объектов на две различные категории: примитивы (изменяемые) и объекты (неизменяемые).
  • Термин “мутация объекта” относится к операциям, которые изменяют объект после его создания. 
  • Хотя примитивные значения, такие как число и т. д., не могут быть изменены, вы всегда можете изменить объекты после их создания. 
  • Поскольку строки в JavaScript неизменяемы, вы не можете изменять их после их создания.
  • Хотя сама мутация не так уж плоха, вы должны управлять ею осторожно, чтобы уменьшить ошибки в ваших приложениях.
  • Вы можете уменьшить или устранить мутацию в JavaScript, следуя рекомендуемым практикам и используя неизменяемые структуры данных.

Source:
https://dzone.com/articles/an-introduction-to-object-mutation-in-javascript