Неизменяемость — очень горячая тема в современном JavaScript, и причина этого, конечно же, в парадигме функционального программирования.
Неизменяемые данные тесно связаны с функциональным подходом, где любая мутация рассматривается как нежелательный побочный эффект. Но сначала давайте углубимся в детали изменчивости и неизменности.
Что такое изменчивость?
Просто чтобы все было ясно, нет ничего плохого в том, что код может быть изменен — API-интерфейс массива JavaScript является изменяемым, и в этом нет ничего плохого. Тем не менее, неправильное использование изменчивости может вызвать побочные эффекты для вашего программного обеспечения. Давайте посмотрим на пример кода ниже:
const person = { name: 'Rodrigo', email: '[email protected]' } // Make a copy of person object const newPerson = person; // Changing the email of the new person newPerson.email = '[email protected]'; console.log(newPerson === person); // true console.log(person); // { name: 'Rodrigo', email: '[email protected]' } console.log(newPerson); // { name: 'Rodrigo', email: '[email protected]' }
Вы можете видеть, что мы копируем объект (person) в другой объект (newPerson) и вносим небольшое изменение в newPerson. Проблема здесь в том, что изменение отражается на обоих объектах.
Это происходит потому, что когда вы назначаете объект переменной в JS, вы фактически назначаете ему ссылку на память, поэтому, когда вы делаете это:
const newPerson = person;
Вы просто копируете эту ссылку, а не реальные значения. Обе переменные указывают на одно и то же место.
Стать неизменным
Неизменяемость — это искусство поддерживать состояние объекта, делая разработку простой, отслеживаемой, тестируемой и уменьшая любые возможные побочные эффекты. Основная идея такова: обновление должно не изменять объект, а создавать новый объект с обновленными данными.
Вместо того, чтобы передавать объект и изменять его, нам будет лучше создать совершенно новый объект:
const person = { name: 'Rodrigo', email: '[email protected]' } const newPerson = Object.assign( {}, person, { email: '[email protected]' } ); console.log(newPerson === person); // false console.log(person) // { name: 'Rodrigo', email: '[email protected]' } console.log(newPerson) // { name: 'Rodrigo', email: '[email protected]' }
Но эй, мы используем ES6, нельзя ли сделать это по-другому? Конечно! Мы можем использовать оператор Spread! Взглянем:
const person = { name: 'Rodrigo', email: '[email protected]' } const newPerson = { ...person, email: '[email protected]' } console.log(newPerson === person); // false - really different objects console.log(person) // { name: 'Rodrigo', email: '[email protected]' } console.log(newPerson) // { name: 'Rodrigo', email: '[email protected]' }
Аккуратно, верно? Опять же, тот же результат и даже более чистый код. Сначала мы создаем новый объект, присваивая {} переменной, затем мы используем оператор «расширения» (…), чтобы скопировать все свойства человека в новый объект. Затем мы определяем новое свойство «электронная почта», которое переопределяет старое. Обратите внимание, что в этом случае порядок имеет значение, если электронная почта: ‘[email protected]’ определена до распространения объекта человека, она будет переопределена значением адреса электронной почты из объекта человека.
Массивы
Во-первых, давайте сделаем небольшой пример того, как вы можете изменить массив:
const fruits = [ 'Orange', 'Apple' ]; const newFruits = characters newFruits.push('Banana'); console.log(fruits === newFruits) // true :-(
Массивы работают так же, как объекты, поэтому вы также можете использовать оператор распространения, чтобы сделать массивы неизменяемыми. Вот как вы можете это использовать:
const fruits = [ 'Orange', 'Apple' ]; const newFruits = [ ...fruits, 'Banana' ]; console.log(fruits === newFruits) // false console.log(fruits) // [ 'Orange', 'Apple' ] console.log(newFruits) // [ 'Orange', 'Apple', 'Banana' ]
Как видите, вы можете довольно легко добиться неизменности, используя простой современный JavaScript! В конце концов, все дело в здравом смысле и понимании того, что на самом деле делает ваш код. Если вы программируете невнимательно, JavaScript может быть непредсказуемым.
Дополнительные материалы на plainenglish.io