Параметры и аргументы: в чём разница
Эти два слова постоянно путают. Параметр — это имя, указанное в определении функции. Аргумент — это значение, которое вы передаёте при её вызове. Логика та же, что в Python и большинстве других языков:
a и b — это параметры. 2 и 3 — аргументы. JavaScript связывает их по позиции: первый аргумент попадает в первый параметр, второй — во второй и так далее. Разница вроде бы мелочь, но именно такими терминами оперируют сообщения об ошибках и документация MDN.
JavaScript и вольное отношение к количеству аргументов
В отличие от многих других языков, JavaScript абсолютно не против, если вы передадите слишком мало или слишком много аргументов. Недостающие параметры получат значение undefined, а лишние просто молча проигнорируются:
Первый вызов выведет Привет, Ada undefined — аргумент last не передали, поэтому он равен undefined, а шаблонные строки спокойно подставляют это значение. Ни ошибки, ни предупреждения. Иногда такая снисходительность удобна, а иногда становится источником багов — как раз для этого и придуманы параметры по умолчанию.
Как задать значение по умолчанию
После имени параметра поставьте = и нужное значение. Если при вызове аргумент не передан (или передан undefined), сработает значение по умолчанию:
Все три вызова работают. В первом и третьем срабатывает значение по умолчанию, а во втором используется переданный аргумент. Это синтаксис ES6 — до 2015 года приходилось писать name = name || "friend" прямо в теле функции, и у такого подхода были свои подводные камни с «ложными» значениями вроде 0 и "".
В качестве значения по умолчанию можно указать любое выражение, а не только литерал:
Выражение вычисляется при каждом вызове, а не один раз при объявлении функции. Поэтому ловушки с изменяемыми значениями по умолчанию, как в Python, тут нет — каждый вызов получает свежий new Date().
Значение по умолчанию подставляется только при undefined
Именно это правило чаще всего сбивает с толку. Параметры по умолчанию срабатывают, когда аргумент равен undefined, а не когда он просто falsy, и не когда это null:
Только последний вызов использует "friend". Если вы явно передаёте null, вы как бы говорите: «значение равно null» — и JavaScript верит вам на слово. То же самое с пустыми строками и нулями: это полноценные значения, а не отсутствующие аргументы.
Если хочется, чтобы null воспринимался как отсутствие аргумента, придётся обрабатывать это вручную:
Оператор ?? (нулевое слияние) считает «пропущенными» и null, и undefined. Подробнее о нём — в одной из следующих глав.
Значения по умолчанию могут ссылаться на предыдущие параметры
Параметры вычисляются слева направо, поэтому в значении по умолчанию можно использовать любой параметр, объявленный ранее:
Вызов с одним аргументом даёт куб. Два аргумента — прямоугольный параллелепипед. Важен порядок объявления: нельзя ссылаться на параметр, который ещё не был объявлен:
function bad(a = b, b = 1) {
return a + b;
}
bad(); // ReferenceError: Cannot access 'b' before initialization
Те же правила, что и для переменных, объявленных через let: использовать до объявления нельзя — будет ошибка.
Значения по умолчанию и деструктуризация
Параметры функции можно деструктурировать и тут же задавать им значения по умолчанию. Этот приём часто встречается, когда функция принимает «объект с настройками»:
Здесь работают два уровня значений по умолчанию. Внутренние (role = "member", active = true) подставляются вместо отсутствующих свойств. А внешнее = {} спасает ситуацию, когда функцию вызывают вообще без аргумента — без него createUser() попытался бы выполнить деструктуризацию undefined и упал бы с ошибкой.
На первый взгляд конструкция выглядит перегруженной, но в современном JavaScript-коде она встречается на каждом шагу. Как только глаз привыкает читать { ... } = {} как «опции со значениями по умолчанию», шаблон распознаётся мгновенно.
Как пропустить средний аргумент
В JavaScript нет именованных аргументов, как в Python. Чтобы пропустить параметр в середине и оставить его значение по умолчанию, нужно явно передать undefined:
Если передать undefined в качестве prefix, сработает значение по умолчанию. Выглядит это так себе. Когда undefined в вызовах встречается у вас постоянно — это явный сигнал перейти на объект с параметрами:
Теперь вызывающий явно указывает, какие значения хочет переопределить, и порядок больше не важен.
Параметры по умолчанию не учитываются в length
Небольшая деталь, которая редко играет роль, но иногда сбивает с толку. Свойство length функции возвращает количество параметров до первого параметра со значением по умолчанию:
Некоторые библиотеки, которые анализируют функции (например, часть инструментов для тестирования и DI), используют length, чтобы подсчитать «обязательные» параметры. Полезно знать, что такое правило существует, но заучивать его не стоит — разве что вы сами пишете подобный инструмент.
Дальше: rest и spread
Параметры по умолчанию хороши, когда набор аргументов известен заранее. Но бывает иначе — нужно, чтобы функция принимала произвольное количество аргументов или передавала целый «пакет» аргументов в другую функцию. Как раз для этого существуют ...rest и оператор расширения (spread), о которых поговорим дальше.
Часто задаваемые вопросы
Как задать значение параметра по умолчанию в JavaScript?
Поставьте = и нужное значение прямо в сигнатуре функции: function greet(name = 'friend') { ... }. Если вызывающий код ничего не передал (или передал undefined), подставится значение по умолчанию. Это синтаксис из ES6 — работает во всех актуальных средах выполнения JavaScript.
Чем параметры отличаются от аргументов?
Параметры — это имена в объявлении функции: у function add(a, b) параметры это a и b. Аргументы — это конкретные значения, которые вы передаёте при вызове: в add(2, 3) аргументы — 2 и 3. Разница важна, когда читаешь сообщения об ошибках и документацию.
Сработает ли значение по умолчанию, если передать null?
Нет. Default срабатывает только на undefined (или когда аргумент вообще не передан). Явно передавая null, вы как бы говорите: «вот тебе значение, и это null» — значит, значение по умолчанию пропускается. На этом часто спотыкаются те, кто пришёл из языков, где null и undefined — одно и то же.
Можно ли в значении по умолчанию сослаться на другой параметр?
Да. Параметры вычисляются слева направо, поэтому значение по умолчанию может использовать предыдущие параметры: function box(width, height = width). В default можно даже вызывать функции — например, function log(msg, time = Date.now()) — и это выражение будет выполняться заново при каждом вызове.