Какие методы массива мутируют его в JavaScript
Что проверяют
Помните ли вы список наизусть и понимаете ли последствия. Вопрос дешёвый на входе, но ведёт к иммутабельности: следом спросят, почему компонент не перерисовался после push в состояние, или попросят отсортировать массив, не трогая исходный.
Как отвечать
Мутирующих методов девять: push, pop, shift, unshift, splice, sort, reverse, fill, copyWithin. Все меняют массив на месте, а sort и reverse вдобавок возвращают ссылку на тот же массив, поэтому const sorted = arr.sort() копии не даёт. Массив меняют и присваивание arr.length = 0, и delete arr[i], который оставляет дыру, не трогая длину.
Немутирующие аналоги стоит назвать сразу: slice, concat, map, filter, flat, flatMap, spread-оператор. С ES2023 у четырёх мутирующих появились копирующие двойники: toSorted, toReversed, toSpliced и with (замена элемента по индексу). Они поддерживаются актуальными браузерами и Node начиная с 20, так что [...arr].sort() больше не единственный путь.
Дальше про последствия:
- React и стор: мутация не меняет ссылку,
useState,memoи селекторы сравнивают черезObject.isи изменения не заметят. В Redux Toolkit «мутация» допустима только внутри редьюсера, там работает Immer с черновиком; - общие данные: массив из props или из кэша могут держать другие места кода, сортировка на месте чинит один экран и ломает соседний;
sortбез компаратора: элементы приводятся к строкам,[10, 9, 1].sort()даёт[1, 10, 9], для чисел нужен компаратор.
Где спотыкаются
Уверенно относят sort и reverse к чистым функциям на том основании, что те возвращают массив.
Путают slice и splice. Первый копирует диапазон, второй режет оригинал и возвращает удалённое.
Сортируют состояние напрямую, не понимают, почему нет перерисовки, и лечат это сменой ключа или принудительным обновлением вместо обычной копии.