Блог

Мутировать или не мутировать в JavaScript

Редакция Lodoss Team
0

Мутации в JavaScript: за и против

Многие проповедуют, что иммутабельность - это лучшее решение для JS. Другие говорят, что иммутабельность ничего не значит для бизнеса, и это просто модный хайп, связанный с популярностью функционального программирования. Если погуглим, мы найдем тонны мнений и статей, описывающих, что такое иммутабельность. В этой статье мы разберем ситуации, когда следует использовать мутации в JavaScript, а когда нет.

Основы

Как и во многих других языках, примитивы неизменяемы в JavaScript. Это означает, что всякий раз, когда мы изменяем примитив, создается его новый экземпляр (его дубликат).

Это ведет к большому количеству преимуществ:
1. Параллельная обработка
2. Сохранение для общего доступа к экземплярам
3. Отсутствие побочных эффектов
4. Нет временной связи
5. Лучше читаемость
6. Меньше потребления памяти
7. Легче кешировать
8. Легко тестировать

Существуют чисто функциональные языки, такие как ELM и Haskell, где невозможно мутировать что-либо. JavaScript не является одним из них. Но есть несколько способов продолжить использовать объекты JS как неизменные примитивы.

Иммутабельность вручную

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

Не изменять объекты в функциях

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

Не изменяйте объекты после создания

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

Избегайте сеттеров любой ценой

Это дополнение к двум вышеприведенным пунктам. Если мы используем сеттеры, мы меняем наши объекты. Так что лучше их не использовать.

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

Immutable.js

Immutable.js от Facebook — небольшая библиотека, которая помогает нам сохранить состояние неизменным. Есть и другие библиотеки, которые работают аналогичным образом (Mori, seamless-immutable), но для этой статьи мы остановимся на Immutable.js.

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

Immutable.js предоставляет множество постоянных неизменяемых структур данных, включая: List, Stack, Map, Ordered Map, Set, Ordered Set и Record.

Или в виде кода:

Несмотря на то, что мы теряем прямой доступ к свойствам объекта, мы можем сосредоточиться на наших целях вместо борьбы с мутациями.

ESLint Immutable

Существует плагин eslint-plugin-immutable, который отключает возможность мутации в JavaScript. В документации упоминаются react/redux,  но можно спокойно использовать плагин и без них.

Плагин добавляет три правила:

1.no-let: форсирует использование const вместо let.
2.no-this: запрещает this и, следовательно, классы ES6.
3.no-mutation: запрещает присвоение значения при прямом доступе к свойствам.

Когда использовать

Параллельная обработка

Это причина номер один, где иммутабельность имеет смысл. Вам не нужно блокировать то, что не меняется. В JS нет реальной параллельной обработки. Вместо этого есть цикл событий. Так что забудьте об этом.

Чтобы избежать побочных эффектов

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

С функциональным программированием

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

Когда не использовать

Часто меняющиеся свойства

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

Огромные структуры данных

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

Выводы

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

To mutate, or not to mutate, in JavaScript

0