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

**Параметры по умолчанию** позволяют задавать формальным параметрам функции значения по умолчанию в случае, если функция вызвана без аргументов, или если параметру явным образом передано значение `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 with JavaScript enabled. Enable JavaScript to view data.

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

* Оригинальное предложение на ecmascript.org