В чем отличие передачи параметров по значению и по ссылке в JavaScript?
Что проверяют
Знаете ли вы, что в JavaScript нет передачи по ссылке, а есть передача значения ссылки. Для Java-разработчика вопрос удобный: семантика та же, что в Java, и интервьюер ждёт, что вы это заметите. Следом просят объяснить, почему присваивание параметру не меняет объект снаружи.
Как отвечать
В JavaScript аргументы всегда передаются по значению. Разница только в том, что это за значение:
- примитивы (
number,string,boolean,bigint,symbol,undefined,null): копируется само значение. Строки ещё и неизменяемы, поменять их «на месте» нельзя вовсе; - объекты, массивы, функции: копируется ссылка. Параметр и внешняя переменная указывают на один объект, поэтому
obj.name = "x"видно снаружи.
Проверка, которая отличает это от настоящей передачи по ссылке: если внутри функции написать obj = { name: "x" }, внешняя переменная не изменится, переназначилась только локальная копия ссылки. При передаче по ссылке, как у ref в C# или & в C++, изменилась бы и внешняя переменная. Такую семантику называют call by sharing.
Параллель с Java прямая: спецификация Java тоже знает только передачу по значению, примитивы копируются, для объектов копируется ссылка. Поэтому ни в Java, ни в JavaScript нельзя написать swap(a, b), который поменяет местами переменные вызывающего кода.
Чтобы не портить входные данные, объект копируют: spread { ...obj } и slice() у массива дают поверхностную копию, structuredClone глубокую.
Где спотыкаются
Говорят «объекты передаются по ссылке». Интервьюер тут же даёт пример с переназначением параметра, и ответ рассыпается.
Считают, что spread копирует объект целиком. Вложенные объекты остаются общими, и мутация copy.address.city меняет оригинал.
Путают передачу аргумента с const: он запрещает переназначить переменную, но не менять содержимое объекта.