Как остановить 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; }
}

Ужасно, но выполняет эту работу.