Параметры по умолчанию

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

Интерактивный пример

Синтаксис

function [name]([param1[ = defaultValue1 ][, ..., paramN[ = defaultValueN ]]]) {
   statements
}

Описание

В JavaScript параметры функции, которым при её вызове не передаются значения, принимают по умолчанию значение undefined. Однако в некоторых случаях может быть полезно задать иное значение по умолчанию. Именно для таких случаев предназначены параметры по умолчанию.

В прошлом для проверки параметров и задания их значений по умолчанию использовался код в теле функции, в котором проверялось, не равны ли значения параметров undefined.

В приведённом ниже примере, в случае если при вызове функции значение для параметра b не передавалось, его значением становилось undefined, и результатом вычисления a * b в функции multiply получалось значение NaN.

js
function multiply(a, b) {
  return a * b;
}

multiply(5, 2); // 10
multiply(5); // NaN !

Чтобы такого не происходило, в теле функции использовался код подобный тому, что находится во второй строчке, где в случае, если функция multiply вызывалась только c одним аргументом, параметру b присваивалось значение 1:

js
function multiply(a, b) {
  b = typeof b !== "undefined" ? b : 1;
  return a * b;
}

multiply(5, 2); // 10
multiply(5); // 5

С появлением в ES2015 параметров по умолчанию стало возможным обходиться без проверки параметров в теле функции. Так, в приведённом выше примере достаточно в заголовке функции указать 1 в качестве значения по умолчанию для параметра b:

js
function multiply(a, b = 1) {
  return a * b;
}

multiply(5, 2); // 10
multiply(5); // 5
multiply(5, undefined); // 5

Примеры

Передача значения undefined в сравнении с передачей других "ложных" значений

Значение по умолчанию присваивается формальному параметру только если при вызове функции значение для данного параметра не было передано или было явным образом передано undefined. Если формальному параметру при вызове передано любое значение, отличное от undefined, в том числе одно из "ложных" значений, таких как false, 0, "", '', ``, null, NaN, то в этом случае значение по умолчанию присвоено параметру не будет. Это иллюстрирует следующий пример:

js
function test(num = 1) {
  console.log(typeof num);
}

// num не передано, или передано undefined:
test(); // 'number' (num получил значение 1)
test(undefined); // 'number' (и здесь num получил значение 1)

// num передано значение null или другое "ложное" значение:
test(""); // 'string' (num получил значение '')
test(null); // 'object' (num получил значение null)

Параметры по умолчанию вычисляются в момент вызова функции

В Javascript параметры по умолчанию вычисляются в момент вызова функции. В отличие от языка Python, при каждом вызове функции создаётся новое лексическое окружение функции.

js
function append(value, array = []) {
  array.push(value);
  return array;
}

append(1); // [1]
append(2); // [2], а не [1, 2]

Это верно и для функций, и для переменных:

js
function callSomething(thing = something()) {
  return thing;
}

let numberOfTimesCalled = 0;
function something() {
  numberOfTimesCalled += 1;
  return numberOfTimesCalled;
}

callSomething(); // 1
callSomething(); // 2

Параметры по умолчанию доступны в следующих параметрах по умолчанию

В параметрах по умолчанию можно использовать значения предыдущих (расположенных левее в списке) параметров:

js
function greet(name, greeting, message = greeting + " " + name) {
  return [name, greeting, message];
}

greet("David", "Hi"); // ["David", "Hi", "Hi David"]
greet("David", "Hi", "Happy Birthday!"); // ["David", "Hi", "Happy Birthday!"]

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

js
function go() {
  return ":P";
}

function withDefaults(
  a,
  b = 5,
  c = b,
  d = go(),
  e = this,
  f = arguments,
  g = this.value,
) {
  return [a, b, c, d, e, f, g];
}
function withoutDefaults(a, b, c, d, e, f, g) {
  switch (arguments.length) {
    case 0:
      a;
    case 1:
      b = 5;
    case 2:
      c = b;
    case 3:
      d = go();
    case 4:
      e = this;
    case 5:
      f = arguments;
    case 6:
      g = this.value;
    default:
  }
  return [a, b, c, d, e, f, g];
}

withDefaults.call({ value: "=^_^=" });
// [undefined, 5, 5, ":P", {value:"=^_^="}, arguments, "=^_^="]

withoutDefaults.call({ value: "=^_^=" });
// [undefined, 5, 5, ":P", {value:"=^_^="}, arguments, "=^_^="]

Инициализация с помощью функций, определяемых в теле функции

Начиная с версии Gecko 33 функции, определяемые в теле самой функции, не могут быть использованы для инициализации параметров по умолчанию; попытка это сделать приведёт к ошибке ReferenceError. Параметры по умолчанию всегда вычисляются до обработки описаний функций, определяемых в теле функции.

js
// Вызовет ошибку ReferenceError!
function f(a = go()) {
  function go() {
    return ":P";
  }
}
f(); // ReferenceError: go is not defined

Параметры без инициализации, следующие после инициализируемых параметров

До появления версии Gecko 26, следующий код приводил к SyntaxError. Это было исправлено в Firefox bug 777060 и с тех пор работает корректно. Аргументы, передаваемые при вызове функции, становятся значениями формальных параметров независимо от наличия у последних инициализации по умолчанию, а также независимо от присутствия у функции других параметров, находящихся правее в списке параметров и не имеющих инициализации.

js
function f(x = 1, y) {
  return [x, y];
}

f(); // [1, undefined];
f(2); // [2, undefined];

Инициализация по умолчанию деструктурированных параметров

При инициализации параметров по умолчанию можно использовать синтаксическую конструкцию деструктурирующего присваивания:

js
function f([x, y] = [1, 2], { z: z } = { z: 3 }) {
  return x + y + z;
}

f(); // 6

Спецификации

Specification
ECMAScript Language Specification
# sec-function-definitions

Совместимость с браузерами

BCD tables only load in the browser

Смотрите также