TypeError: Reduce of empty array with no initial value(Тип ошибки: уменьшение пустого массива без начального значения)

Сообщение

TypeError: уменьшение пустого массива без начального значения

Тип ошибки

Что пошло не так?

В JavaScript существует несколько уменьшающих функций :

Эти функции дополнительно принимают значение initialValue (которое будет использоваться в качестве первого аргумента для первого вызова колбэка). Однако если начальное значение не указано, будет использоваться первый элемент Array или TypedArray в качестве начального значения. Эта ошибка возникает, когда предоставляется пустой массив, так как в этом случае не может быть возвращено начальное значение.

Примеры

Неправильные примеры

Эта проблема часто возникает в сочетании с фильтром (Array.prototype.filter(), TypedArray.prototype.filter() (en-US)) который удалит все элементы списка. Таким образом, не оставляя ни одного для использования в качестве начального значения.

js
var ints = [0, -1, -2, -3, -4, -5];
ints
  .filter((x) => x > 0) // удаление всех элементов
  .reduce((x, y) => x + y); // no more elements to use for the initial value.

Аналогично, та же проблема может возникнуть, если в селекторе есть опечатка или непредвиденное количество элементов в списке:

js
var names = document.getElementsByClassName("names");
var name_list = Array.prototype.reduce.call(
  names,
  (acc, name) => acc + ", " + name,
);

Правильные примеры

Эти проблемы могут быть решены двумя различными способами.

Один из способов - фактически предоставить initialValue в качестве нейтрального элемента оператора, например 0 для сложения, 1 для умножения или пустую строку для объединения

js
var ints = [0, -1, -2, -3, -4, -5];
ints
  .filter((x) => x < 0) // removes all elements
  .reduce((x, y) => x + y, 0); // the initial value is the neutral element of the addition

Другим способом было бы два для обработки пустого случая, или перед вызовом reduce, или в обратном вызове после добавления неожиданного фиктивного начального значения.

js
var names = document.getElementsByClassName("names");

var name_list1 = "";
if (names1.length >= 1)
  name_list1 = Array.prototype.reduce.call(
    names,
    (acc, name) => acc + ", " + name,
  );
// name_list1 == "" when names is empty.

var name_list2 = Array.prototype.reduce.call(
  names,
  (acc, name) => {
    if (acc == "")
      // initial value
      return name;
    return acc + ", " + name;
  },
  "",
);
// name_list2 == "" when names is empty.

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