Параметры, аргументы и значения по умолчанию

функции≈ 7 минут

Здесь будет встроен видео-разбор темы (5–7 минут, YouTube / RuTube / VK Видео) — тем, кто лучше воспринимает на слух, текст ниже не обязателен.

Параметры — это ярлыки на пустых ящиках, которые функция расставляет заранее; аргументы — то, что вы кладёте в эти ящики при вызове. Разберёмся, что произойдёт, если ящиков больше, чем вещей, и почему переданный внутрь объект можно случайно испортить.

Разделы темы:·

Параметры — имена в скобках при объявлении функции. Это обычные локальные переменные, которые появляются в момент вызова. Аргументы — конкретные значения, которые вы подставляете, когда вызываете функцию.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Связь между ними — позиционная. Первый аргумент попадает в первый параметр, второй — во второй, и никакие имена переменных снаружи на это не влияют. Поэтому перепутанный порядок — не ошибка синтаксиса, а тихо неверный ответ.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Параметр — имя в объявлении, аргумент — то, что реально приехало при вызове. В разговоре их путают все, но на собеседовании спрашивают.

Если аргумент могут не передать, задайте параметру запасное значение прямо в объявлении: параметр = значение. Оно подставится только тогда, когда аргумента нет.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Умолчание — это выражение, которое вычисляется при каждом вызове. Значит, в нём можно ссылаться на параметры, объявленные левее, и даже вызывать функции. Справа налево не работает: параметр, до которого очередь ещё не дошла, недоступен.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Движок сравнивает аргумент именно с undefined. Пустой вызов и явный undefined для него одно и то же, а вот null — полноценное значение, и функция примет его как есть.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

JavaScript не сверяет количество аргументов с количеством параметров. Передали больше — лишнее просто некуда положить, и оно отбрасывается. Передали меньше — оставшиеся параметры получат undefined. Ошибки не будет ни в том, ни в другом случае, будет странный результат. А сколько параметров объявлено, знает сама функция: sum.length.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
ВызовabРезультат
sum(1, 2)123
sum(1, 2, 3)123
sum(1)1undefinedNaN
sum()undefinedundefinedNaN

Тогда соберите их в массив остаточным параметром ...имя — он всегда последний в списке. Старый способ, псевдомассив arguments, ещё встречается в чужом коде, но в новом его не пишут: это не настоящий массив, а у стрелочной функции своего arguments нет вовсе. Обе роли трёх точек разбирает статья «Spread и rest: три точки в двух ролях».

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Число, строка, булево значение попадают в параметр копией. Внутри функции вы работаете со своей коробкой: можно присваивать в неё что угодно, наружная переменная об этом не узнает.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Это удобная гарантия: функция, принимающая примитивы, физически не может испортить данные вызывающего кода. Всё, что она хочет сообщить, она возвращает через return.

С объектами и массивами копируется не содержимое, а ссылка — адрес одного и того же объекта в памяти. Параметр и внешняя переменная указывают в одну точку, поэтому изменение поля внутри функции видно снаружи.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

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

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Когда параметров становится больше трёх, вызов вида createUser("Аня", true, false, 5) невозможно прочитать. Приём: принимать один объект и сразу разбирать его в скобках функции — умолчания при этом работают как обычно, а порядок перестаёт иметь значение.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Одна тонкость: вызов createUser() вообще без аргумента упадёт — разбирать нечего. Лечится умолчанием для всего объекта: function createUser({ name, role = "user" } = {}). Разбор самого узора — в статье «Деструктуризация»: там же и про вложенные структуры, и про новое имя переменной.

  • Параметры объявляются в скобках функции, аргументы передаются при вызове; связываются они по позиции, а не по именам переменных снаружи.
  • Запись «параметр = значение» подставляет умолчание только вместо undefined; null умолчание не включает, а само выражение вычисляется при каждом вызове.
  • Лишние аргументы молча отбрасываются, недостающие параметры становятся undefined — ошибки не будет, будет неверный результат.
  • Примитив попадает в параметр копией: что бы функция с ним ни делала, внешняя переменная не изменится.
  • Объект передаётся копией ссылки: менять его поля внутри — значит менять оригинал, а переприсваивать параметр целиком — бессмысленно.

1/3Что выведет console.log(f(3)) для function f(a, b = a * 2) { return a + b; }?

2/3function hi(name = "гость") { return name; } — что вернёт hi(null)?

3/3function f(obj) { obj = { n: 2 }; } — const o = { n: 1 }; f(o); чему равно o.n?

Цена со скидкой

Допишите функцию price(sum, discount): она возвращает сумму, уменьшенную на discount процентов и округлённую до целого. Если скидку не передали, цена остаётся прежней.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Умолчание 0 делает вызов без второго аргумента корректным: вычитаем ноль процентов и получаем исходную сумму, никаких if не нужно.

jsлистинг · не запускается
Листинг только для чтения: этот код не запускается в браузере.

Не испортить чужой объект

Функция withBonus должна вернуть новый объект с полем score, увеличенным на 10, и при этом не тронуть исходный. Сейчас она возвращает тот же самый объект.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Спред-синтаксис копирует поля в новый объект, а score перезаписывается уже в копии. Исходный user остаётся нетронутым — именно поэтому такой стиль безопаснее, чем user.score += 10.

jsлистинг · не запускается
Листинг только для чтения: этот код не запускается в браузере.