Frage Wie man Array.forEach wie Kurzschluß kurzschließt?


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

Wie kann ich das mit dem neuen tun? forEach Methode in JavaScript? Ich habe versucht "Return", "Return false" und "Break". Break stürzt ab und return macht nichts weiter als Iteration.


1008
2018-04-14 21:57


Ursprung


Antworten:


Es gibt keine eingebaute Fähigkeit dazu break im forEach. Um die Ausführung zu unterbrechen, müssen Sie eine Ausnahme auslösen. z.B.

var BreakException = {};

try {
  [1, 2, 3].forEach(function(el) {
    console.log(el);
    if (el === 2) throw BreakException;
  });
} catch (e) {
  if (e !== BreakException) throw e;
}

JavaScript-Ausnahmen sind nicht besonders hübsch. Ein traditionelles for Schleife ist möglicherweise besser geeignet, wenn Sie es wirklich brauchen break im Inneren.

Benutzen Array#some

Verwenden Sie stattdessen Array#some:

[1, 2, 3].some(function(el) {
  console.log(el);
  return el === 2;
});

Das funktioniert weil some kehrt zurück true sobald einer der in Array-Reihenfolge ausgeführten Callbacks zurückkehrt trueKurzschließen der Ausführung des Restes.

some, seine Umkehrung every (Das wird auf einem stoppen return false), und forEach sind alle ECMAScript Fifth Edition - Methoden, die zum Array.prototype in Browsern, wo sie fehlen.


1404
2018-04-14 22:02



Es gibt jetzt einen noch besseren Weg, dies in ECMAScript2015 (aka ES6) mit dem neuen zu tun für die Schleife. Zum Beispiel druckt dieser Code die Array-Elemente nicht nach der Nummer 5:

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (let el of arr) {
  console.log(el);
  if (el === 5) {
    break;
  }
}

Aus den Dokumenten:

Beide für in und für ... von Anweisungen durchlaufen etwas. Der Hauptunterschied zwischen ihnen besteht darin, über was sie iterieren. Das für in Die Anweisung iteriert die aufzählbaren Eigenschaften eines Objekts in der ursprünglichen Reihenfolge. Das für ... von Die Anweisung iteriert über Daten, die für iterierbare Objektdefinitionen definiert sind.

Benötigen Sie den Index in der Iteration? Sie können verwenden Array.entries():

for (const [index, el] of arr.entries()) {
  if ( index === 5 ) break;
}

165
2017-08-19 16:43



Sie können verwenden jeden Methode:

[1,2,3].every(function(el) {
    return !(el === 1);
});

für alte Browser-Unterstützung:

if (!Array.prototype.every)
{
  Array.prototype.every = function(fun /*, thisp*/)
  {
    var len = this.length;
    if (typeof fun != "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this &&
          !fun.call(thisp, this[i], i, this))
        return false;
    }

    return true;
  };
}

mehr Details Hier.


154
2017-07-19 09:18



Zitat aus der MDN Dokumentation von Array.prototype.forEach():

Es gibt keine Möglichkeit zu stoppen oder zu brechen ein forEach() Schleife anders als   durch Auslösen einer Ausnahme. Wenn Sie solch ein Verhalten brauchen, das .forEach() Methode ist die falsches Werkzeug, verwenden Sie stattdessen eine einfache Schleife. Wenn Sie die Array-Elemente für ein Prädikat testen und einen booleschen Rückgabewert benötigen, können Sie verwenden every() oder some() stattdessen.

Verwenden Sie für Ihren Code (in der Frage), wie von @bobince vorgeschlagen Array.prototype.some() stattdessen. Es passt sehr gut zu Ihrem Anwendungsfall.

Array.prototype.some() führt die Callback-Funktion für jedes im Array vorhandene Element einmal aus, bis eine Callback-Funktion gefunden wird, die einen Truthy-Wert zurückgibt (ein Wert, der bei der Konvertierung in a wahr wird) Boolean). Wenn solch ein Element gefunden wird, some() gibt sofort True zurück. Andernfalls, some() gibt false zurück. Callback wird nur für Indizes des Arrays aufgerufen, denen Werte zugewiesen sind; Es wird nicht für Indizes aufgerufen, die gelöscht wurden oder denen nie Werte zugewiesen wurden.


45
2018-01-06 21:16



Leider wird es in diesem Fall viel besser sein, wenn Sie nicht verwenden forEach. Verwenden Sie stattdessen einen regulären for Schleife und es wird jetzt genau so funktionieren, wie Sie es erwarten würden.

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

38
2017-08-25 20:03



Überlegen Sie zu verwenden jqueryist es each Methode, da es ermöglicht, falsche interne Callback-Funktion zurückzugeben:

$.each(function(e, i) { 
   if (i % 2) return false;
   console.log(e)
})

Lodash Bibliotheken bietet auch takeWhile Methode, die mit map / reduce / fold usw. verkettet werden kann:

var users = [
  { 'user': 'barney',  'active': false },
  { 'user': 'fred',    'active': false },
  { 'user': 'pebbles', 'active': true }
];

_.takeWhile(users, function(o) { return !o.active; });
// => objects for ['barney', 'fred']

// The `_.matches` iteratee shorthand.
_.takeWhile(users, { 'user': 'barney', 'active': false });
// => objects for ['barney']

// The `_.matchesProperty` iteratee shorthand.
_.takeWhile(users, ['active', false]);
// => objects for ['barney', 'fred']

// The `_.property` iteratee shorthand.
_.takeWhile(users, 'active');
// => []

24
2018-04-14 22:06



Wenn du es benutzen möchtest Dean Edwards Vorschlag und werfen Sie den StopIteration Fehler, um aus der Schleife zu brechen, ohne den Fehler zu fangen, können Sie die folgende Funktion verwenden (ursprünglich von hier):

// Use a closure to prevent the global namespace from be polluted.
(function() {
  // Define StopIteration as part of the global scope if it
  // isn't already defined.
  if(typeof StopIteration == "undefined") {
    StopIteration = new Error("StopIteration");
  }

  // The original version of Array.prototype.forEach.
  var oldForEach = Array.prototype.forEach;

  // If forEach actually exists, define forEach so you can
  // break out of it by throwing StopIteration.  Allow
  // other errors will be thrown as normal.
  if(oldForEach) {
    Array.prototype.forEach = function() {
      try {
        oldForEach.apply(this, [].slice.call(arguments, 0));
      }
      catch(e) {
        if(e !== StopIteration) {
          throw e;
        }
      }
    };
  }
})();

Der obige Code gibt Ihnen die Möglichkeit, Code wie den folgenden auszuführen, ohne eigene try-catch-Klauseln zu verwenden:

// Show the contents until you get to "2".
[0,1,2,3,4].forEach(function(val) {
  if(val == 2)
    throw StopIteration;
  alert(val);
});

Eine wichtige Sache zu erinnern ist, dass dies nur die Array.prototype.forEach Funktion aktualisiert, wenn sie bereits existiert. Wenn es nicht bereits existiert, wird es das nicht ändern.


14
2017-07-05 19:32



Aus Ihrem Codebeispiel sieht es so aus Array.prototype.find ist was du suchst: Array.prototype.find () und Array.prototype.findIndex () 

[1, 2, 3].find(function(el) {
    return el === 2;
}); // returns 2

13
2018-01-15 20:20



Kurze Antwort: verwenden for...break dafür oder ändern Sie Ihren Code, um das Brechen zu vermeiden forEach. Verwende nicht .some() oder .every() emulieren for...break. Schreiben Sie Ihren Code neu, um es zu vermeiden for...break Schleife oder verwenden for...break. Jedes Mal, wenn Sie diese Methoden als verwenden for...break alternativer Gott tötet Kätzchen.

Lange Antwort:

.some() und .every() beide kehren zurück boolean Wert, .some() kehrt zurück true Wenn ein Element zurückgegeben wird, für das die übergebene Funktion zurückgegeben wurde true, jede Rückkehr false Wenn ein Element zurückgegeben wird, für das die übergebene Funktion zurückgegeben wurde false. Dies ist, was diese Funktionen bedeuten. Das Verwenden von Funktionen für das, was sie nicht bedeuten, ist viel schlimmer als das Verwenden von Tabellen für das Layout anstelle von CSS, weil es jeden frustriert, der Ihren Code liest.

Außerdem ist die einzige Möglichkeit, diese Methoden zu verwenden for...break Alternative ist es, Nebenwirkungen zu erzeugen (ändern Sie einige Variablen außerhalb von .some() Callback-Funktion), und das ist nicht viel anders for...break.

Also, mit .some() oder .every() wie for...break Loop-Alternative ist nicht frei von Nebenwirkungen, das ist nicht viel sauberer dann for...breakdas ist frustrierend, also ist das nicht besser.

Sie können Ihren Code immer neu schreiben, so dass keine Notwendigkeit besteht for...break. Sie können das Array mit Filtern filtern .filter(), Sie können Array mit trennen .slice() und so weiter, dann benutze es .forEach() oder .map() für diesen Teil des Arrays.


8
2017-07-29 12:34



Diese Lösung wurde auf einer anderen Website gefunden. Sie können forEach in ein Try / Catch-Szenario einbinden.

if(typeof StopIteration == "undefined") {
 StopIteration = new Error("StopIteration");
}

try {
  [1,2,3].forEach(function(el){
    alert(el);
    if(el === 1) throw StopIteration;
  });
} catch(error) { if(error != StopIteration) throw error; }

Weitere Details hier: http://dea.edwards.name/weblog/2006/07/enum/


3
2018-04-14 22:07



Wenn Sie nach der Iteration nicht auf Ihr Array zugreifen müssen, können Sie die Länge des Arrays auf 0 setzen. Wenn Sie es nach der Iteration noch benötigen, können Sie es mit slice klonen.

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

Oder mit einem Klon:

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;
});

Was ist eine viel bessere Lösung als zufällige Fehler in Ihrem Code zu werfen.


3
2018-06-04 09:38