Как мутирование массива влияет на контроль данных
Что проверяют
Знаете ли вы, какие методы массива меняют исходные данные, и понимаете ли, почему React и стор-библиотеки на мутацию реагируют молчанием. Следом обычно просят найти баг в коде, где компонент не перерисовывается после push, или спрашивают про глубокое копирование.
Как отвечать
Начните с разделения методов:
- мутирующие:
push,pop,shift,unshift,splice,sort,reverse,fill. Меняют массив на месте, ссылка остаётся прежней; - немутирующие:
map,filter,slice,concat, спред[...arr], а с ES2023 копирующие версииtoSorted,toReversed,toSplicedиwith.
Потом объясните, при чём тут контроль данных. Массив передаётся по ссылке, и если его меняет одна часть кода, изменение видят все, кто держит ту же ссылку: props родителя, кэш, соседний компонент. Отследить, кто и когда поменял данные, становится трудно.
В React это ещё и прямой баг: setState сравнивает старое и новое значение через Object.is, и после items.push(x); setItems(items) ссылка та же, поэтому рендера не будет. Так же сравниваются зависимости useEffect, useMemo и props в React.memo. Правильно setItems(prev => [...prev, x]).
Упомяните инструменты. Object.freeze замораживает только верхний уровень. structuredClone делает глубокую копию, но она дорогая. Immer, встроенный в Redux Toolkit, позволяет писать «мутирующий» код в редьюсере, а на выходе получать новый объект. Во Vue 3 реактивность построена на Proxy, и мутации там отслеживаются штатно, так что ответ зависит от фреймворка.
Где спотыкаются
Считают спред глубокой копией. [...users] создаёт новый массив, но объекты внутри те же, и copy[0].name = 'x' меняет исходные данные.
Вызывают sort() прямо на props или на массиве из стора, забывая, что он сортирует на месте. Лечится toSorted() или копией перед сортировкой.
Говорят, что мутация запрещена всегда. Внутри функции над локальным массивом, который никто снаружи не видит, push в цикле нормален и быстрее цепочки копий.