22

Краткое завершение Array.forEach, как при вызове break

13

Проблема:

Я пытаюсь использовать метод forEach в JavaScript для итерации по массиву, но у меня возникла проблема с прекращением итерации при выполнении определённого условия. В частности, вот мой код:

[1, 2, 3].forEach(function(el) {
    if (el === 1) break;
});

Я ожидаю, что итерация прекратится, когда элемент массива равен 1. Однако использование break вызывает ошибку, а return и return false никак не останавливают итерацию, и цикл продолжается.

Вопрос: Как мне правильно остановить итерацию с использованием метода forEach?

5 ответ(ов)

1

К сожалению, в данном случае будет гораздо лучше, если вы не будете использовать forEach. Вместо этого используйте обычный цикл for, и всё будет работать именно так, как вы ожидали.

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

Краткий ответ: используйте for...break для этих случаев или измените свой код, чтобы избежать использования break в forEach. Не используйте .some() или .every(), чтобы эмулировать for...break. Перепишите свой код, чтобы избежать for...break, или используйте for...break. Каждый раз, когда вы используете эти методы в качестве альтернативы for...break, котенок умирает.

Длинный ответ:

Методы .some() и .every() оба возвращают логическое значение: .some() возвращает true, если есть хотя бы один элемент, для которого переданная функция возвращает true, а .every() возвращает false, если хотя бы один элемент возвращает false. Именно это и означают эти функции. Использовать функции не по назначению гораздо хуже, чем использовать таблицы для оформления вместо CSS, потому что это расстраивает всех, кто читает ваш код.

Кроме того, единственный способ использовать эти методы в качестве альтернативы for...break — это создать побочные эффекты (изменить некоторые переменные вне колбэк-функции .some()), и это не сильно отличается от for...break.

Таким образом, использование .some() или .every() вместо цикла for...break не свободно от побочных эффектов, это не намного чище, чем for...break, и это вызывает неудовлетворение, поэтому это не лучше.

Вы всегда можете переписать свой код так, чтобы избежать необходимости в for...break. Вы можете отфильтровать массив, используя .filter(), вы можете разбить массив с помощью .slice(), и так далее, а затем использовать .forEach() или .map() для нужной части массива.

0

Ваш код реализует функцию forEach, которая принимает массив и обратный вызов (cb). Она проходит по элементам массива и вызывает cb для каждого элемента. Если в процессе выполнения обратного вызова вызывается функция _break, то выполнение цикла прерывается. Давайте разберемся, как это работает, и почему это может быть полезно.

Вот ваша реализация функции forEach:

function forEach(array, cb) {
  var shouldBreak;
  function _break() { shouldBreak = true; }
  for (var i = 0, bound = array.length; i < bound; ++i) {
    if (shouldBreak) { break; }
    cb(array[i], i, array, _break);
  }
}

// Пример использования
forEach(['a','b','c','d','e','f'], function (char, i, array, _break) {
  console.log(i, char);
  if (i === 2) { _break(); }
});

Как это работает:

  1. Внутри функции forEach создается переменная shouldBreak и функция _break, которая изменяет значение shouldBreak на true.
  2. Далее идет цикл for, который проходит по всем элементам массива.
  3. В начале каждой итерации проверяется, была ли вызвана функция _break. Если да, то выполнение цикла прекращается.
  4. Если нет, функция cb вызывается с текущим элементом, индексом элемента, полным массивом и возможностью прервать (функцией _break).

Пример использования

В примере вы передаете массив букв и функцию обратного вызова, которая выводит индекс и символ. Когда индекс достигает 2 (т.е. на третьем элементе массива), вызывается функция _break, что прерывает дальнейшее выполнение цикла.

Почему это может быть полезно

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

Замечания

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

0

Это просто решение, которое я придумал для решения проблемы. Я вполне уверен, что это исправляет ту проблему, с которой столкнулся задавший вопрос:

Array.prototype.each = function(callback) {
    if (!callback) return false;
    for (var i = 0; i < this.length; i++) {
        if (callback(this[i], i) === false) break;
    }
};

Теперь вы можете вызвать его следующим образом:

var myarray = [1, 2, 3];
myarray.each(function(item, index) {
    // делаем что-то с элементом
    // если (item != somecondition) return false; 
});

Возвращение false внутри функции обратного вызова приведет к выходу из цикла. Дайте знать, если это решение не сработает.

0

Если вам не нужно обращаться к массиву после его итерации, вы можете просто выйти из него, установив длину массива равной 0. Если же массив все-таки нужен после итерации, вы можете создать его клон с помощью метода slice.

Вот пример, где длина массива устанавливается в 0:

[1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) {
  if (index === 3) arr.length = 0;
});

Или вот как можно сделать с клоном:

var x = [1,3,4,5,6,7,8,244,3,5,2];

x.slice().forEach(function (item, index, arr) {
  if (index === 3) arr.length = 0;
});

Это заметно лучший вариант, чем выбрасывать случайные ошибки в вашем коде.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь