как остановить Javascript forEach? [дубликат]
этот вопрос уже есть ответ здесь:
Я играю с nodejs и мангустом-пытаюсь найти конкретный комментарий в глубоких комментариях, вложенных с рекурсивной функцией и foreach внутри. Есть ли способ, чтобы остановить nodejs цикле foreach? Как я понимаю каждый forEach итерация-это функция,и я не могу просто сделать "перерыв", только "возврат", но это не остановит foreach.
function recurs(comment){
comment.comments.forEach(function(elem){
recurs(elem);
//if(...) break;
});
}
13 ответов:
вы не можете оторваться от
forEach
. Однако я могу придумать три способа подделать его.1. Уродливый Путь: передать второй аргумент
forEach
to использовать в качестве контекста, и хранить логическое значение там, а затем использоватьif
. Это выглядит ужасно.2. Спорный Способ: окружите все это в
try-catch
блок и бросить исключение, когда вы хотите, чтобы сломать. Это выглядит довольно плохо и может повлиять производительность, но может быть инкапсулирован.3. Интересный Способ используйте
every()
.['a', 'b', 'c'].every(function(element, index) { // Do your thing, then: if (you_want_to_break) return false else return true })
можно использовать
some()
вместо этого, если вы предпочитаетеreturn true
для того чтобы сломать.
вырвавшись из массив#forEach не возможно. (Вы можете проверить исходный код, который реализует его в Firefox на ссылке, чтобы подтвердить это.)
вместо этого вы должны использовать нормальный
for
петли:function recurs(comment) { for (var i = 0; i < comment.comments.length; ++i) { var subComment = comment.comments[i]; recurs(subComment); if (...) { break; } } }
(или, если вы хотите быть немного умнее об этом и
comment.comments[i]
- всегда объект:)function recurs(comment) { for (var i = 0, subComment; subComment = comment.comments[i]; ++i) { recurs(subComment); if (...) { break; } } }
как указывали другие, вы не можете отменить
forEach
петли, но вот мое решение:ary.forEach(function loop(){ if(loop.stop){ return; } if(condition){ loop.stop = true; } });
конечно, это на самом деле не нарушает цикл, он просто предотвращает выполнение кода на всех элементах после "break"
в некоторых случаях
Array.some
будет, вероятно, соответствовать требованиям.
Я думаю, вы хотите использовать массив.прототип.найти Find сломает себя, когда он найдет ваше конкретное значение в массиве.
var inventory = [ {name: 'apples', quantity: 2}, {name: 'bananas', quantity: 0}, {name: 'cherries', quantity: 5} ]; function findCherries(fruit) { return fruit.name === 'cherries'; } console.log(inventory.find(findCherries)); // { name: 'cherries', quantity: 5 }
Вы можете использовать lodash это
forEach
функция, если вы не против использования сторонних библиотек.пример:
var _ = require('lodash'); _.forEach(comments, function (comment) { do_something_with(comment); if (...) { return false; // Exits the loop. } })
var f = "how to stop Javascript forEach?".split(' '); f.forEach(function (a,b){ console.info(b+1); if (a == 'stop') { console.warn("\tposition: \'stop\'["+(b+1)+"] \r\n\tall length: " + (f.length)); f.length = 0; //<--!!! } });
Array.forEach
не может быть нарушена и с помощьюtry...catch
или хакерские методы, такие какArray.every
илиArray.some
только сделает ваш код труднее понять. Есть только два решения этой проблемы:1) Используйте старый
for
цикл: это будет наиболее совместимое решение, но может быть очень трудно читать при использовании часто в больших блоках кода:var testArray = ['a', 'b', 'c']; for (var key = 0; key < testArray.length; key++) { var value = testArray[key]; console.log(key); // This is the key; console.log(value); // This is the value; }
2) используйте новую спецификацию ECMA6 (2015) в случаях, когда совместимость не является проблемой. Обратите внимание, что даже в 2016 году, только несколько браузеров и IDE предлагают хорошую поддержку для этой новой спецификации. Хотя это работает для итерационных объектов (например, массивов), если вы хотите использовать это на неитерабельных объектах, вам нужно будет использовать
Object.entries
метод. Этот метод едва ли доступен по состоянию на 18 июня 2016 года, и даже Chrome требует специального флага для его включения:chrome://flags/#enable-javascript-harmony
. Для массивов вам не понадобится все это, но совместимость остается проблемой:var testArray = ['a', 'b', 'c']; for (let [key, value] of testArray.entries()) { console.log(key); // This is the key; console.log(value); // This is the value; }
3) Многие люди согласятся, что ни первый, ни второй вариант-хорошие кандидаты. Пока Вариант 2 не станет новым стандартом, большинство популярных библиотек, таких как AngularJS и jQuery, предлагают свои собственные методы цикла, которые могут превосходить все, что доступно в JavaScript. Также для тех, кто еще не использует эти большие библиотеки и которые ищут легкие варианты, такие решения, как этой может использоваться и будет почти на одном уровне с ECMA6 при сохранении совместимости со старыми браузерами.
forEach не ломается по возвращении, есть уродливые решения, чтобы получить эту работу, но я предлагаю не использовать его, вместо этого попробуйте использовать
Array.prototype.some
илиArray.prototype.every
var ar = [1,2,3,4,5]; ar.some(function(item,index){ if(item == 3){ return true; } console.log("item is :"+item+" index is : "+index); });
ниже код будет перерыв цикла foreach как только условие будет выполнено, ниже приведен пример
var array = [1,2,3,4,5]; var newArray = array.slice(0,array.length); array.forEach(function(item,index){ //your breaking condition goes here example checking for value 2 if(item == 2){ array.length = array.indexOf(item); } }) array = newArray;
вы можете выйти из цикла forEach, если перезаписать метод массива:
(function(){ window.broken = false; Array.prototype.forEach = function(cb, thisArg) { var newCb = new Function("with({_break: function(){window.broken = true;}}){("+cb.replace(/break/g, "_break()")+"(arguments[0], arguments[1], arguments[2]));}"); this.some(function(item, index, array){ newCb(item, index, array); return window.broken; }, thisArg); window.broken = false; } }())
пример:
[1,2,3].forEach("function(x){\ if (x == 2) break;\ console.log(x)\ }")
к сожалению, с этим решением вы не можете использовать обычный перерыв внутри ваших обратных вызовов, вы должны обернуть недопустимый код в строки и собственные функции не работают напрямую (но вы можете обойти это)
счастливый ломать!
Wy не использовать простой возврат?
function recurs(comment){ comment.comments.forEach(function(elem){ recurs(elem); if(...) return; });
он вернется из функции 'recurs'. Я использую его вот так. Хотя это не будет ломаться от forEach, но от всей функции, в этом простом примере это может работать
jQuery предоставляет
each()
метод, а неforEach()
. Вы можете вырваться изeach
вернутьсяfalse
.forEach()
является частью стандарта ECMA-262, и единственный способ вырваться из этого, о котором я знаю, - это выбросить исключение.function recurs(comment) { try { comment.comments.forEach(function(elem) { recurs(elem); if (...) throw "done"; }); } catch (e) { if (e != "done") throw e; } }
некрасиво, но работает.