Как остановить Javascript для каждого?
Я играю с nodejs и mongoose - пытаясь найти конкретный комментарий в глубоких комментариях, вложенных с рекурсивными func и foreach внутри. Есть ли способ остановить nodejs forEach? Поскольку я понимаю, что каждая forEach итерация является функцией, и я не могу просто "сломать", а "вернуться", но это не остановит foreach.
function recurs(comment){
comment.comments.forEach(function(elem){
recurs(elem);
//if(...) break;
});
}
Ответы
Ответ 1
Вы не можете выйти из forEach
. Я могу придумать три способа подделать это.
1. Ugly Way: передайте второй аргумент forEach
в в качестве контекста и сохраните там логическое значение, затем используйте if
. Это выглядит ужасно.
2. Спорный путь: объедините все в блоке try-catch
и выбросьте исключение, когда вы хотите сломать. Это выглядит довольно плохо, и может повлиять на производительность, но может быть инкапсулирован.
3. Fun Way: используйте 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
сломаться.
Ответ 2
Нарушение Array # 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;
}
}
}
Ответ 3
Как указывали другие, вы не можете отменить цикл forEach
, но здесь мое решение:
ary.forEach(function loop(){
if(loop.stop){ return; }
if(condition){ loop.stop = true; }
});
Конечно, это фактически не нарушает цикл, он просто предотвращает выполнение кода для всех элементов, следующих за "break"
Ответ 4
В некоторых случаях Array.some
, вероятно, выполнит требования.
Ответ 5
Вы можете использовать функцию Lodash forEach
, если вы не возражаете против использования сторонних библиотек.
Пример:
var _ = require('lodash');
_.forEach(comments, function (comment) {
do_something_with(comment);
if (...) {
return false; // Exits the loop.
}
})
Ответ 6
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; //<--!!!
}
});
Ответ 7
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) Многие люди согласятся, что ни первый, ни второй вариант не являются хорошими кандидатами. Пока второй вариант не станет новым стандартом, большинство популярных библиотек, таких как AngularJS и jQuery, предлагают свои собственные методы цикла, которые могут превосходить все, что доступно в JavaScript. Также для тех, кто еще не использует эти большие библиотеки и ищет облегченные варианты, такие решения, как this, могут быть использованы и будут почти равны с ECMA6, сохраняя совместимость со старыми браузерами.
Ответ 8
Я предполагаю, что вы хотите использовать Array.prototype. 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 }
Ответ 9
Ниже код разбивает цикл 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;
Ответ 10
forEach не прерывается по возвращении, есть уродливые решения для получения этой работы, но я предлагаю не использовать его, вместо этого попробуйте использовать Array.prototype.some
или Array.prototype.every
var ar = [1,2,3,4,5];
ar.some(function(item,index){
if(item == 5){
return;
}
console.log("item is :"+item+" index is : "+index);
});
Ответ 11
Вы можете выйти из цикла forEach, если вы перезаписываете метод Array:
(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)\
}")
К сожалению, с помощью этого решения вы не можете использовать обычный разрыв внутри своих обратных вызовов, вы должны обернуть недействительный код в строках, а собственные функции не работают напрямую (но вы можете обойти это)
Счастливое нарушение!
Ответ 12
Не использовать простой возврат?
function recurs(comment){
comment.comments.forEach(function(elem){
recurs(elem);
if(...) return;
});
он вернется из функции "recurs". Я использую его так. Althougth это не будет прерываться от forEach, а от целой функции, в этом простом примере это может работать
Ответ 13
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; }
}
Ужасно, но выполняет эту работу.