При программировании мутация объекта подразумевает изменение состояния или данных объекта после его создания. Другими словами, операция, которая изменяет атрибуты объекта в JavaScript, известна как мутация объекта. Мутация объекта изменяет значения объекта напрямую, что делает это сложным, особенно в приложениях, где несколько операций могут пытаться одновременно читать или записывать в объект.
В этой статье представлен обзор мутации объектов в JavaScript с соответствующими примерами кода по необходимости.
Типы данных в JavaScript
Типы данных обозначают тип данных, который может содержать переменная или объект. JavaScript поддерживает две различные категории типов данных: примитивные и определенные пользователем или ссылочные типы.
Примитивные типы данных
В JavaScript все примитивные типы данных неизменяемы по своей природе, т. е. их нельзя изменить после их создания. Числа, логические значения, строки, BigInt, неопределенные значения, нулевые значения, символы и объекты являются примерами примитивных типов.
Определенные пользователем или ссылочные типы данных
Определенные пользователем типы данных или ссылочные типы данных – это объекты, созданные с использованием примитивных типов или комбинации примитивных и определенных пользователем типов. Типичными примерами определенных пользователем или ссылочных типов являются объекты и массивы.
Присвоение и повторное присвоение переменных в JavaScript
Когда вы присваиваете переменной примитивного типа значение другой переменной примитивного типа variable, обе переменные содержат схожие значения, но хранятся в разных местах памяти. Например, предположим, что у вас есть две переменные varA
и varB
, и вы присваиваете одну переменную другой следующим образом:
var varA = 100;
var varB = varA;
console.log(varB);
Когда вы выполняете приведенный выше код, число 100 будет отображено на консоли. Теперь вы изменяете значения одной из двух переменных (например, varB
) следующим образом.
var varA = 100;
var varB = varA;
varB = 500;
console.log(varA);
Обратите внимание, как значение переменной varB
изменилось на 500. Когда вы печатаете значение varA
, оно по-прежнему будет равно 100. Это происходит потому, что переменные varA
и varB
хранятся в двух разных ячейках памяти. Таким образом, если вы измените одну из них, новое или измененное значение не отразится на других переменных.
Что такое мутация объектов в JavaScript?
В JavaScript тип данных объекта может принадлежать к одной из двух категорий: примитивный или непримитивный. В то время как примитивные типы неизменяемы, т.е. вы не можете их изменить после создания, вы можете изменять непримитивные типы, т.е. объекты и массивы. Объекты всегда позволяют изменять свои значения. Следовательно, вы можете изменять состояние полей для изменяемого типа, не создавая новый экземпляр.
Мутации объектов могут создавать несколько проблем, таких как следующие:
- Измененные объекты могут часто приводить к гонкам из-за проблем с параллелизмом и безопасностью потоков.
- Мутация может привести к сложностям в исходном коде из-за проблем предсказуемости и безопасности потоков
- Мутация часто может привести к ошибкам, которые могут быть сложными для идентификации в исходном коде приложения
- Мутация делает тестирование и отладку кода сложными, потому что отслеживание кода, использующего мутацию, становится вызовом
Примеры кода, демонстрирующие мутацию объектов
Мутация объектов может происходить в любом из следующих сценариев:
- Добавление, изменение или удаление свойств
- Использование методов, способных проявлять мутацию
Когда вы изменяете свойства объекта, непосредственно или косвенно, вы суть изменяете объект. В следующем фрагменте кода показано, как вы можете изменить объект, изменив его свойство.
const author = { id: 1, name: "Joydip Kanjilal"};
author.id = 2; author.city = "Hyderabad, INDIA";
console.log(author);
В предыдущем фрагменте кода мы создаем объект с именем автор, содержащий два свойства, а именно, id
и name
. В то время как свойство id
используется для хранения id
записи автора, свойство name
хранит имя автора. Обратите внимание, как мы изменяем объект автора, изменив значение, относящееся к свойству id
. Затем мы добавляем новое свойство с именем city в объект автора и присваиваем ему значение.
При запуске предыдущего фрагмента кода свойства и их значения объекта автора будут отображены как показано ниже:
{ name: 'Joydip Kanjilal', city: 'Hyderabad, INDIA' }
Когда вы передаете объект в функцию или присваиваете его переменной в JavaScript, вы фактически передаете ссылку на объект, а не копию. Это означает, что любое изменение, внесенное в новый объект, созданный путем передачи объекта или присваивания его переменной, будет применяться ко всем ссылкам на фактический объект.
Рассмотрим следующий фрагмент кода, показывающий, как можно создать объект в JavaScript, а затем присвоить его переменной.
const objA = { id: 1, name: 'Joydip Kanjilal',
city: 'Hyderabad, INDIA', pincode: 500089 }
const objB = objA;
objB.pincode = 500034;
console.log(objA);
В предыдущем фрагменте кода объект objA
присваивается переменной objB
, и значение свойства pincode объекта objA
изменяется, т.е. объект objA
мутируется. При выполнении программы будет отображены следующие данные.
{ id: 1, name: 'Joydip Kanjilal', city: 'Hyderabad, INDIA', pincode: 500034 }
Обратите внимание, что значение свойства pincode было изменено.
Предотвращение мутации объектов в JavaScript
В JavaScript можно предотвратить мутацию несколькими способами, включая следующие:
- Использование клонирования объекта с помощью метода
Object.assign()
или оператора spread (…) - Использование метода
Object.seal()
для предотвращения добавления или удаления свойств объекта - Использование метода
Object.freeze()
для предотвращения добавления, редактирования или удаления свойств объекта
Использование клонирования
Обратитесь к следующему фрагменту кода, показывающему, как можно клонировать объект в JavaScript с использованием оператора spread.
let originalObj = { x: 10, y: 100 }; let clonedObj = { originalObj };
Здесь имя клонированного объекта clonedObj
, и он идентичен оригинальному объекту с именем originalObj
. Таким образом, если вы отобразите значения двух свойств этих двух объектов, результаты будут одинаковыми.
Теперь измените значение одного из свойств клонированного объекта с именем clonedObj
на желаемое значение, как показано в следующем фрагменте кода.
clonedObj.x = 50;
Теперь напишите следующий фрагмент кода для отображения значения свойства с именем x
, относящегося к двум объектам originalObj
и clonedObj
.
console.log(originalObj.x);
console.log(clonedObj.x);
Когда вы запустите программу, вы увидите, что значение свойства x
в оригинальном объекте остается неизменным. Значения будут отображены в консоли, как показано ниже:
10
50
Использование метода Object.freeze()
Метод Object.freeze()
может сделать объект неизменным, предотвращая любые изменения его свойств.
const author = { id: 1, name: "Joydip Kanjilal",
city: "Hyderabad", state: "Telengana",
country: "India", pincode: 500089};
Object.freeze(author);
author.city = "Bangalore";
author.state = "Karnataka";
author.pincode = 560010;
console.log(author);
Когда вы выполните предыдущий фрагмент кода, результаты будут аналогичны следующему:
{
id: 1,
name: 'Joydip Kanjilal',
city: 'Hyderabad',
state: 'Telangana',
country: 'India',
pincode: 500089
}
Как видно из вывода, даже если вы присвоили значения свойствам city и state, и pincode, никаких изменений не произошло. Таким образом, данные, содержащиеся в любом из свойств объекта, остаются неизменными.
Использование метода Object.seal()
Вы также можете использовать метод Object.seal()
для предотвращения мутации объектов в JavaScript. Этот метод позволяет изменять значения существующих свойств, но вы не можете модифицировать или удалять любые свойства объекта. Приведенный ниже пример кода иллюстрирует это:
const author = { id: 1, name: "Joydip Kanjilal",
city: "Hyderabad", state: "Telangana",
country: "India", pincode: 500089};
Object.seal(author);
author.city = "Bangalore";
author.state = "Karnataka";
author.pincode = 560005;
author.booksauthored = 3;
console.log(author);
В предыдущем фрагменте кода, хотя изменения свойств объекта с именем автор будут разрешены, добавление или удаление свойств объекта не будет разрешено. Когда вы запустите программу, вы увидите, что значения измененных свойств отражены в результате, но операции по добавлению или удалению свойств будут проигнорированы. Вот как будет выглядеть вывод на консоли:
{
id: 1,
name: 'Joydip Kanjilal',
city: 'Bangalore',
state: 'Karnataka',
country: 'India',
pincode: 560005
}
Использование метода Object.defineProperty()
Вы также можете использовать метод Object.defineProperty()
в JavaScript для управления изменяемостью отдельных свойств объекта. В следующем фрагменте кода показано, как вы можете использовать этот метод, чтобы запретить изменения значения, содержащегося в свойстве, чья изменяемость ограничена.
const author = { id: 1, name: "Joydip Kanjilal"};
Object.defineProperty(author, "booksauthored",
{
value: 3,
writable: false,
});
author.booksauthored = 5;
console.log(author.booksauthored);
Когда вы выполните предыдущий фрагмент кода, вы увидите, что на консоли отображается число 3.
Основные моменты
- JavaScript категоризирует типы объектов на две различные категории: примитивы (изменяемые) и объекты (неизменяемые).
- Термин “мутация объекта” относится к операциям, которые изменяют объект после его создания.
- Хотя примитивные значения, такие как число и т. д., не могут быть изменены, вы всегда можете изменить объекты после их создания.
- Поскольку строки в JavaScript неизменяемы, вы не можете изменять их после их создания.
- Хотя сама мутация не так уж плоха, вы должны управлять ею осторожно, чтобы уменьшить ошибки в ваших приложениях.
- Вы можете уменьшить или устранить мутацию в JavaScript, следуя рекомендуемым практикам и используя неизменяемые структуры данных.
Source:
https://dzone.com/articles/an-introduction-to-object-mutation-in-javascript