Что передается по ссылке при переборе объектов в map и что можно изменить
Что проверяют
Понимаете ли вы, что именно лежит в переменной, когда там объект, и что из этого следует при переборе массива. Это способ за минуту выяснить, откуда у кандидата берутся странные баги с мутациями и почему интерфейс иногда не перерисовывается.
Как отвечать
Сформулируйте точно: в JavaScript всё передаётся по значению, просто значением переменной с объектом является ссылка. В колбэк map приходит копия ссылки на тот же объект, отсюда три следствия:
- изменение свойства видно снаружи: объект в исходном массиве тот же самый;
- переприсваивание параметра снаружи не видно: поменялась только локальная копия ссылки;
- сам
mapисходный массив не трогает, он собирает новый из того, что вы вернули.
const users = [{ name: "Аня" }];
users.map((u) => { u.name = "Б"; return u; }); // исходный объект изменён
users.map((u) => ({ ...u, name: "Б" })); // исходный целПравильная привычка: map для преобразования без побочных эффектов, новые объекты через разворот или structuredClone, а если нужно именно подействовать на каждый элемент, берите forEach. Помните про глубину: разворот копирует верхний уровень, вложенные объекты и массивы остаются общими. const запрещает переприсваивание переменной, но содержимое объекта не защищает, а Object.freeze замораживает тоже лишь верхний уровень.
Где спотыкаются
Говорят, что объекты передаются по ссылке, и после этого не могут объяснить, почему присваивание нового объекта параметру снаружи ничего не меняет. Формулировка через копию ссылки снимает вопрос целиком.
Второе: копируют разворотом и считают копию полной. Вложенный массив остаётся общим, правка в копии прилетает в оригинал, и дефект доживает до продакшена, потому что на плоских объектах всё работало.
Третье: мутируют состояние в React. Интерфейс не обновляется: ссылка на массив прежняя, сравнение пропсов поверхностное, мемоизация видит те же значения. Реже встречается обратное: копию делают на каждый рендер там, где данные не менялись, и теряют мемоизацию.