Книга: Выразительный JavaScript

Абстрагируем обход массива

Абстрагируем обход массива

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

В предыдущей главе мы несколько раз встречали такой цикл:

var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
  var current = array[i];
  console.log(current);
}

Код пытается сказать: «для каждого элемента в массиве – вывести его в консоль». Но он использует обходной путь – с переменной для подсчёта i, проверкой длины массива, и объявлением дополнительной переменной current. Мало того, что он не очень красив, он ещё и является почвой для потенциальных ошибок. Мы можем случайно повторно использовать переменную i, вместо length написать lenght, перепутать переменные i и current, и т. п.

Давайте абстрагируем его в функцию. Можете придумать способ это сделать?

Довольно просто написать функцию, обходящую массив и вызывающую для каждого элемента console.log.

function logEach(array) {
  for (var i = 0; i < array.length; i++)
    console.log(array[i]);
}

Но что, если нам надо делать что-то другое, нежели выводить элементы в консоль? Поскольку «делать что-то» можно представить как функцию, а функции – это просто переменные, мы можем передать это действие как аргумент:

function forEach(array, action) {
  for (var i = 0; i < array.length; i++)
    action(array[i]);
}
forEach(["Тили", "Мили", "Трямдия"], console.log);
// ? Тили
// ? Мили
// ? Трямдия

Часто можно не передавать заранее определённую функцию в forEach, а создавать функцию прямо на месте.

var numbers = [1, 2, 3, 4, 5], sum = 0;
forEach(numbers, function(number) {
  sum += number;
});
console.log(sum);
// ? 15

Выглядит похоже на классический цикл for, с телом цикла, записанным в блоке. Однако, теперь тело находится внутри функции, и также внутри скобок вызова forEach. Поэтому его нужно закрыть как фигурной, так и круглой скобкой.

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

Вообще, нам даже не нужно писать самим forEach. Это стандартный метод массивов. Так как массив уже передан в качестве переменной, над которой мы работаем, forEach принимает только один аргумент – функцию, которую нужно выполнить для каждого элемента.

Для демонстрации удобства этого подхода вернёмся к функции из предыдущей главы. Она содержит два цикла, проходящих по массивам:

function gatherCorrelations(journal) {
  var phis = {};
  for (var entry = 0; entry < journal.length; entry++) {
    var events = journal[entry].events;
    for (var i = 0; i < events.length; i++) {
      var event = events[i];
      if (!(event in phis))
        phis[event] = phi(tableFor(event, journal));
    }
  }
  return phis;
}

Используя forEach мы делаем запись чуть короче и гораздо чище.

function gatherCorrelations(journal) {
  var phis = {};
  journal.forEach(function(entry) {
    entry.events.forEach(function(event) {
      if (!(event in phis))
        phis[event] = phi(tableFor(event, journal));
    });
  });
  return phis;
}

Оглавление книги


Генерация: 1.543. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз