Серия Изучение ES6 продолжается рассмотрением параметров по умолчанию в ECMAScript 6. Если вы еще не знаете о let и const в ES6, вам следует ознакомиться с предыдущей статьей Обзор блока. догнать.

TL;DR

ES6 позволяет заголовкам функций определять значения по умолчанию для параметров, помечая их как необязательные:

[js]
function getData(data, useCache=true) {
if (useCache) {
console.log('использование кеша для', data);
}
else {
console.log('кэш не используется', данные);
}
}

// `useCache` отсутствует и является `undefined`.
// поэтому `useCache ` по умолчанию имеет значение `true`
getData({q:'churches+in+Pittsburg'});
[/js]

Этот быстрый пример — лишь верхушка айсберга. Обязательно ознакомьтесь с полным набором примеров кода обработки параметров (часть репозитория Learning ES6 Github) и продолжайте читать.

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

JavaScript позволяет вызывать функции с меньшим количеством параметров, чем объявляет функция. В ES5 эта возможность использовалась для неявной поддержки необязательных параметров. Вот версия ES5 примера ES6, использованного выше:

[js]
function getData(data, useCache) {
if (useCache === undefined)
useCache = true;

if (useCache) {
console.log('используем кеш для', данные);
}
else {
console.log('не используем кеш', данные);

}

getData({q:'церкви+в+Питтсбурге'});
[/js]

Как видите, useCache объявлен как параметр функции getData, но вызывающая сторона не передала для него значение. В результате движок JavaScript передает значение undefined, которое проверяет функция getData, чтобы по умолчанию установить значение true.

Еще раз эквивалент ES6 выглядит так:

[js]
function getData(data, useCache=true) {
if (useCache) {
console.log('использование кеша для', data);
}
else {
console.log('кэш не используется', данные);
}
};

// `useCache` отсутствует и является `undefined`.
// поэтому `useCache ` по умолчанию имеет значение `true`
getData({q:'churches+in+Pittsburg'});
[/js]

В ES6 тело функции не должно иметь дело с логикой по умолчанию. Он находится в заголовке функции, где и должен быть. Также любому читателю кода ясно, что значение useCache по умолчанию будет равно true, если его не указать.

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

Обязательные параметры

В примере параметр данных считается обязательным, так как он не имеет значения по умолчанию. Однако движок JS не выдаст ошибку, если вы оставите обязательный параметр неуказанным из-за поддержки обратной совместимости. В ES5 для принудительного применения необходимых параметров вы должны были посмотреть длину аргументов или проверить, не определен ли параметр, и выдать ошибку.

Есть несколько способов самостоятельно реализовать необходимые параметры в ES6, но все они создают визуальный беспорядок. Лучший (и самый умный) подход исходит от Акселя Раушмайера (через Аллена Вирфса-Брока):

[js]
/**
* Вызывается, если параметр отсутствует и вычисляется выражение
*, указывающее значение по умолчанию.
*/
function throwIfMissing( ) {
throw new Error('Отсутствует параметр');
}
function func(requiredParam = throwIfMissing()) {
// некоторая реализация
}
[/js]

Если requiredParam не указан или не определен, будет выброшена ошибка, а это именно то, что нам нужно. Просто немного странно иметь функцию в качестве значения по умолчанию, которая не возвращает значение, а только выдает ошибку. Говоря о вызовах функций как о значениях по умолчанию…

Непримитивные значения по умолчанию

В отличие от других языков программирования, которые поддерживают значения по умолчанию (например, C#), значение по умолчанию в ES6 не обязательно должно быть примитивным значением, таким как String, Number или Boolean. Значением по умолчанию может быть объект, массив или функция. Значение по умолчанию может быть даже результатом вызова выражения или функции.

[js]
function getWidth() {
console.log('getWidth call');
return 7;
}
function drawRect(
width =getWidth(),
height=width * 2,
options={color:'red'}
) {
console.log(width, height, options); }

// `getWidth` вызывается для получения значения по умолчанию
// значение для `width`, поскольку оно не указано.
// вывод:
// вызывается getWidth
// 7, 14, {color:'red'}
drawRect();

// `getWidth` не вызывается, потому что `width`
// указан. `height` по-прежнему имеет значение по умолчанию
// 2x `width`.
// вывод:
// 17, 34, {color:'red'}
drawRect(17 );

// `height` больше не устанавливается по умолчанию равной 2x `width`
// но параметры по-прежнему устанавливаются по умолчанию.
// ouput:
// 4, 11, {color:'red' }
drawRect(4, 11);

// ничего не установлено по умолчанию
// вывод:
// 7,5, 11, {color:'blue'}
drawRect(7.5, 11, {color:'blue'}) ;
[/js]

Довольно круто, да? Вы заметили, что значение высоты по умолчанию — это выражение, использующее значение ширины? Вы можете использовать другие переменные, объявленные в заголовке функции, если они стоят перед рассматриваемой переменной. Также стоит отметить, что выражения или функции не выполняются, если переменная не требует значения по умолчанию.

Порядок параметров по умолчанию

Кроме того, в отличие от других языков программирования, в ES6 значения по умолчанию могут быть в любом месте заголовка функции, даже перед параметрами, не имеющими значений по умолчанию.

Давайте посмотрим на пример:

[js]
function drawCube(x, y=7, z) {
console.log(‘cube’, x, y, z);
};

// `y` по умолчанию, но `x` и `z` не являются
// поэтому они `undefined`.
// вывод: cube, undefined, y, undefined
нарисоватьКуб();

// `y` по-прежнему используется по умолчанию, а `z` — нет.
// вывод: cube, 2.5, 7, undefined
drawCube(2.5);

// вывод: cube, 9, 15, undefined
drawCube(9, 15);

// вывод: куб, 4, 1.7, 18
drawCube(4, 1.7, 18);

// `y` снова по умолчанию
// вывод: cube, 11, 7, 8.8
drawCube(11, undefined, 8.8);

// `null` не переводит `y` в значение по умолчанию
// вывод: cube, 14, null, 72
drawCube(14, null, 72);
[/js]

Как видите, значение по умолчанию для y не срабатывает, если только y и z не указаны или не задано явное значение y. В двух словах, undefined запускает значения по умолчанию.

Может быть не сразу понятно, почему TC39 выбрал неопределенные значения триггера по умолчанию. Логику лучше всего пояснить на паре примеров.

Сначала взгляните на этот пример из Заметок о встрече TC39 Рика Уолдрона (24 июля 2012 г.):

[js]
function setLevel(newLevel = 0) {
light.intensity = newLevel;
}
function setOptions(options) {
// Отсутствуют свойства в ` options` will
// приведет к передаче `undefined` в
// `setLevel`, который вызовет значение по умолчанию
setLevel(options.dimmerLevel);

// здесь больше кода…
}
setOptions({speed:5});
[/js]

Нам не нужно генерировать значение по умолчанию для options.dimmerLevel в setOptions. Вместо этого, поскольку значение undefined вызывает значения по умолчанию, а отсутствующие свойства объектов не определены, мы можем делегировать значение по умолчанию для setLevel.

Еще один пример из книги Акселя Раушмайера Изучаем ES6:

[js]
функция умножить (x = 1, y = 1) {
вернуть x * y;
}
функция квадрат (x) {
вернуть умножить ( х, х);
}

// `x` будет `undefined` и по умолчанию
// для `x` и `y` в `multiply`
Square();
[/js]

Квадратной функции не нужно беспокоиться о значении x по умолчанию, и она может делегировать эту задачу умножению. Поскольку x не указан в вызове Square, его значение не определено. И поскольку undefined передается для умножения для x и y, их значения устанавливаются по умолчанию.

Поддержка движка JavaScript

Согласно Таблице совместимости ECMAScript 6, только следующие движки JavaScript поддерживают параметры по умолчанию:

  • Трейсер
  • Вавилон
  • Машинопись
  • Fire Fox
  • Вебкит

Это означает, что Edge, Chrome, Safari и Node еще не поддерживают параметры по умолчанию. Вам в значительной степени нужно использовать транспилятор, чтобы использовать эту функциональность сейчас.

Дополнительные ресурсы

Как всегда, вы можете посетить Learning ES6 страницу примеров для Learning ES6 репозитория Github, где вы найдете весь код, использованный в этой статье, работающий изначально. в браузере (для тех, которые поддерживают параметры по умолчанию).

Вы также можете практиковать все, чему научились на ES6 Katas. Он использует подход TDD (разработка через тестирование), чтобы вы могли реализовать функции ES6, чтобы все тесты прошли. Я очень рекомендую это!

Наконец, если этой информации недостаточно, вы можете прочитать еще больше о параметрах по умолчанию в ES6:

Далее…

На следующей неделе мы продолжим серию Изучение ES6 и рассмотрим, как новый оператор rest/spread в ES6 может помочь нам писать более понятный код. До тех пор…

к вашему сведению

Эта серия Learning ES6 на самом деле представляет собой кросс-публикацию серии с таким же названием в моем личном блоге benmvp.com. Содержание почти такое же, за исключением того, что в этой серии будет дополнительная информация о том, как мы конкретно используем ES6 здесь, в Eventbrite Engineering. Я также буду рассматривать функции в другом порядке, чем в моем личном блоге. Первоначальный пост в блоге о параметрах по умолчанию был частью более крупного поста обработка параметров.