Frage For-jedes über ein Array in JavaScript?


Wie kann ich alle Einträge in einem Array mit JavaScript durchlaufen?

Ich dachte, es wäre so:

forEach(instance in theArray)

Woher theArray ist mein Array, aber das scheint falsch zu sein.


3782
2018-02-17 13:51


Ursprung


Antworten:


TL; DR

  • Benutze es nicht for-in es sei denn, Sie verwenden es mit Sicherheitsmaßnahmen oder sind sich zumindest dessen bewusst, warum es Sie beißen könnte.
  • Ihre besten Wetten sind normalerweise

    • ein for-of Schleife (nur ES2015 +),
    • Array#forEach (spec | MDN) (oder seine Verwandten.) some und so) (nur ES5 +),
    • ein einfaches altmodisch for Schleife,
    • oder for-in mit Sicherheitsvorkehrungen.

Aber da ist viele mehr zu entdecken, weiterlesen ...


JavaScript verfügt über eine leistungsfähige Semantik zum Durchlaufen von Arrays und Array-ähnlichen Objekten. Ich habe die Antwort in zwei Teile aufgeteilt: Optionen für echte Arrays und Optionen für Dinge, die nur Array-mögen, so wie die arguments Objekt, andere iterierbare Objekte (ES2015 +), DOM-Sammlungen und so weiter.

Ich werde schnell feststellen, dass Sie die ES2015-Optionen verwenden können jetzt, sogar auf ES5-Motoren, durch transpilierend ES2015 bis ES5. Suche nach "ES2015 transpiling" / "ES6 transpiling" für mehr ...

Okay, schauen wir uns unsere Möglichkeiten an:

Für tatsächliche Arrays

Sie haben drei Möglichkeiten in ECMAScript 5 ("ES5"), die momentan am weitesten unterstützte Version, und zwei weitere hinzugefügt ECMAScript 2015 ("ES2015", "ES6"):

  1. Benutzen forEach und verwandte (ES5 +)
  2. Verwenden Sie ein einfaches for Schleife
  3. Benutzen for-in  korrekt
  4. Benutzen for-of (verwende einen Iterator implizit) (ES2015 +)
  5. Verwenden Sie explizit einen Iterator (ES2015 +)

Einzelheiten:

1. Verwenden forEach und die damit verbundenen

In jeder vage-modernen Umgebung (also nicht IE8), wo Sie Zugriff auf die haben Array Features, die von ES5 hinzugefügt wurden (direkt oder mit Polyfills), können Sie verwenden forEach (spec | MDN):

var a = ["a", "b", "c"];
a.forEach(function(entry) {
    console.log(entry);
});

forEach akzeptiert eine Callback-Funktion und optional einen Wert, der als verwendet werden soll this wenn dieser Callback aufgerufen wird (oben nicht verwendet). Der Rückruf wird für jeden Eintrag in dem Array in der Reihenfolge aufgerufen, in der nicht existierende Einträge in Sparse-Arrays übersprungen werden. Obwohl ich oben nur ein Argument verwendet habe, wird der Callback mit drei aufgerufen: Der Wert jedes Eintrags, der Index dieses Eintrags und ein Verweis auf das Array, über das Sie gerade iterieren (falls Ihre Funktion es nicht bereits griffbereit hat) ).

Es sei denn, Sie unterstützen veraltete Browser wie IE8 (NetApps zeigt im September 2016 einen Marktanteil von etwas mehr als 4%), können Sie gerne verwenden forEach in einer allgemeinen Webseite ohne eine Unterlegscheibe. Wenn Sie veraltete Browser unterstützen müssen, Shimming / Polyfilling forEach ist leicht gemacht (Suche nach "es5 shim" für verschiedene Optionen).

forEach hat den Vorteil, dass Sie keine Indizierungs- und Wertvariablen im enthaltenden Gültigkeitsbereich deklarieren müssen, da sie als Argumente für die Iterationsfunktion bereitgestellt werden und somit genau auf diese Iteration beschränkt sind.

Wenn Sie über die Laufzeitkosten für einen Funktionsaufruf für jeden Array-Eintrag besorgt sind, seien Sie nicht; Einzelheiten.

Zusätzlich, forEach ist die "Schleife durch alle" -Funktion, aber ES5 definiert mehrere andere nützliche "arbeiten Sie Ihren Weg durch das Array und Dinge tun" -Funktionen, einschließlich:

  • every (Stoppt die Schleife beim ersten Mal, wenn der Callback zurückkehrt false oder etwas falsch)
  • some (Stoppt die Schleife beim ersten Mal, wenn der Callback zurückkehrt true oder etwas truthy)
  • filter (erstellt ein neues Array mit Elementen, in die die Filterfunktion zurückkehrt true und diejenigen weglassen, wo es zurückkehrt false)
  • map (erstellt ein neues Array aus den vom Callback zurückgegebenen Werten)
  • reduce (baut einen Wert auf, indem wiederholt der Callback aufgerufen wird, vorhergehende Werte übergeben werden; siehe die Spezifikation für die Details; nützlich zum Summieren des Inhalts eines Arrays und vieler anderer Dinge)
  • reduceRight (mögen reduce, funktioniert aber in absteigender statt aufsteigender Reihenfolge)

2. Verwenden Sie ein einfaches for Schleife

Manchmal sind die alten Wege die besten:

var index;
var a = ["a", "b", "c"];
for (index = 0; index < a.length; ++index) {
    console.log(a[index]);
}

Wenn sich die Länge des Arrays während der Schleife nicht ändert und es sich um leistungsabhängigen Code handelt (unwahrscheinlich), könnte eine etwas kompliziertere Version, die die Länge nach vorne packt, a sein sehr klein etwas schneller:

var index, len;
var a = ["a", "b", "c"];
for (index = 0, len = a.length; index < len; ++index) {
    console.log(a[index]);
}

Und / oder rückwärts zählen:

var index;
var a = ["a", "b", "c"];
for (index = a.length - 1; index >= 0; --index) {
    console.log(a[index]);
}

Aber mit modernen JavaScript-Engines ist es selten, dass Sie das letzte bisschen Saft herausholen müssen.

In ES2015 und höher können Sie Ihre Index- und Wertvariablen lokal für die for Schleife:

let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
    let value = a[index];
}
//console.log(index); // Would cause "ReferenceError: index is not defined"
//console.log(value); // Would cause "ReferenceError: value is not defined"

Und wenn du das tust, nicht nur value aber auch index wird für jede Schleifeniteration neu erstellt, dh im Schleifenkörper erstellte Verschlüsse behalten einen Verweis auf index (und value) erstellt für diese spezifische Iteration:

let divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
    divs[index].addEventListener('click', e => {
        alert("Index is: " + index);
    });
}

Wenn Sie fünf Divs hätten, würden Sie "Index ist: 0" erhalten, wenn Sie auf den ersten und "Index ist: 4" geklickt haben, wenn Sie auf den letzten geklickt haben. Das macht nicht arbeiten, wenn Sie verwenden var Anstatt von let.

3. Verwenden for-in  korrekt

Sie werden Leute sagen, die Sie benutzen sollen for-in, aber das ist nicht was for-in ist für. for-in Schleifen durch die aufzählbare Eigenschaften eines Objekts, nicht die Indizes eines Arrays. Die Bestellung ist nicht garantiertnicht einmal in ES2015 (ES6). ES2015 definiert eine Reihenfolge für Objekteigenschaften (über [[OwnPropertyKeys]], [[Enumerate]]und Dinge, die sie mögen Object.getOwnPropertyKeys), aber es nicht Definieren Sie das for-in wird dieser Reihenfolge folgen. (Details in diese andere Antwort.)

Trotzdem, es kann nützlich sein, insbesondere für spärlich Arrayswenn Sie angemessene Sicherheitsvorkehrungen treffen:

// `a` is a sparse array
var key;
var a = [];
a[0] = "a";
a[10] = "b";
a[10000] = "c";
for (key in a) {
    if (a.hasOwnProperty(key)  &&        // These are explained
        /^0$|^[1-9]\d*$/.test(key) &&    // and then hidden
        key <= 4294967294                // away below
        ) {
        console.log(a[key]);
    }
}

Beachten Sie die beiden Überprüfungen:

  1. Dass das Objekt seine hat besitzen Eigenschaft mit diesem Namen (nicht eine es erbt von seinem Prototyp), und

  2. Der Schlüssel ist eine numerische Basis-10-Zeichenfolge in der normalen Zeichenfolgenform und der Wert ist <= 2 ^ 32 - 2 (entspricht 4.294.967.294). Woher kommt diese Nummer? Es ist Teil der Definition eines Array-Index in der Spezifikation. Andere Zahlen (nicht ganze Zahlen, negative Zahlen, Zahlen größer als 2 ^ 32 - 2) sind keine Array-Indizes. Der Grund dafür ist 2 ^ 32 - 2 ist, dass das den größten Indexwert eins niedriger als 2 ^ 32 macht - 1Dies ist der Maximalwert eines Arrays length kann haben. (Zum Beispiel passt die Länge eines Arrays in eine 32-Bit-Ganzzahl ohne Vorzeichen.) (Reagiert auf RobG, um auf einen Kommentar hinzuweisen auf meinem Blogbeitrag dass mein vorheriger Test nicht ganz richtig war.)

Das ist bei den meisten Arrays ein kleines bisschen Overhead pro Schleifenwiederholung, aber wenn Sie ein spärlich Array, kann es eine effizientere Möglichkeit zum Schleifen sein, da es nur für tatsächlich existierende Einträge eine Schleife bildet. Z. B. werden für das obige Array insgesamt drei Schleifen wiederholt (für Schlüssel "0", "10", und "10000"- Denk dran, das sind Saiten, nicht 10,001 mal.

Nun, du wirst das nicht jedes Mal schreiben wollen, also kannst du das in dein Toolkit schreiben:

function arrayHasOwnIndex(array, prop) {
    return array.hasOwnProperty(prop) && /^0$|^[1-9]\d*$/.test(prop) && prop <= 4294967294; // 2^32 - 2
}

Und dann würden wir es so benutzen:

for (key in a) {
    if (arrayHasOwnIndex(a, key)) {
        console.log(a[key]);
    }
}

Oder wenn Sie nur an einem Test interessiert sind, der "gut genug für die meisten Fälle" ist, können Sie dies verwenden, aber während es in der Nähe ist, ist es nicht ganz korrekt:

for (key in a) {
    // "Good enough" for most cases
    if (String(parseInt(key, 10)) === key && a.hasOwnProperty(key)) {
        console.log(a[key]);
    }
}

4. Verwenden for-of (verwende einen Iterator implizit) (ES2015 +)

ES2015 fügt hinzu Iteratoren zu JavaScript. Der einfachste Weg, Iteratoren zu verwenden, ist der neue for-of Erklärung. Es sieht aus wie das:

var val;
var a = ["a", "b", "c"];
for (val of a) {
    console.log(val);
}

Ausgabe:

ein
b
c

Unter der Decke bekommt das eine Iterator aus dem Array und durchläuft es, um die Werte daraus zu erhalten. Dies hat nicht das Problem, dass zu verwenden for-in hat, weil es einen Iterator verwendet, der durch das Objekt (das Array) definiert ist, und Arrays definieren, dass ihre Iteratoren durch iterieren Einträge (nicht ihre Eigenschaften). nicht wie for-in In ES5 ist die Reihenfolge, in der die Einträge besucht werden, die numerische Reihenfolge ihrer Indizes.

5. Verwenden Sie explizit einen Iterator (ES2015 +)

Manchmal möchten Sie vielleicht einen Iterator verwenden ausdrücklich. Du kannst das auch, obwohl es viel klüger ist als for-of. Es sieht aus wie das:

var a = ["a", "b", "c"];
var it = a.values();
var entry;
while (!(entry = it.next()).done) {
    console.log(entry.value);
}

Der Iterator ist ein Objekt, das der Iterator-Definition in der Spezifikation entspricht. Es ist next Methode gibt eine neue zurück Ergebnisobjekt jedes Mal, wenn Sie es anrufen. Das Ergebnisobjekt hat eine Eigenschaft, doneund uns sagen, ob es fertig ist und eine Immobilie value mit dem Wert für diese Iteration. (done ist optional, wenn es so wäre false, value ist optional, wenn es so wäre undefined.)

Die Bedeutung von value variiert je nach Iterator; Arrays unterstützen (mindestens) drei Funktionen, die Iteratoren zurückgeben:

  • values(): Dies ist die eine, die ich oben verwendet habe. Es gibt an jedem einen Iterator zurück value ist der Array-Eintrag für diese Iteration ("a", "b", und "c" im obigen Beispiel).
  • keys(): Gibt an jedem einen Iterator zurück value ist der Schlüssel für diese Iteration (also für unsere a Oben wäre das "0", dann "1", dann "2").
  • entries(): Gibt an jedem einen Iterator zurück value ist ein Array in der Form [key, value] für diese Iteration.

Für Array-ähnliche Objekte

Abgesehen von echten Arrays gibt es auch Array-ähnlich Objekte mit a length Eigenschaft und Eigenschaften mit numerischen Namen: NodeList Instanzen, die arguments Objekt usw. Wie durchlaufen wir ihre Inhalte?

Verwenden Sie eine der obigen Optionen für Arrays

Zumindest einige und möglicherweise die meisten oder sogar alle der oben genannten Array-Ansätze gelten häufig gleichermaßen für Array-artige Objekte:

  1. Benutzen forEach und verwandte (ES5 +)

    Die verschiedenen Funktionen auf Array.prototype sind "absichtlich generisch" und können normalerweise über Array-ähnliche Objekte verwendet werden Function#call oder Function#apply. (Siehe Vorbehalt für vom Host bereitgestellte Objekte am Ende dieser Antwort, aber es ist ein seltenes Problem.)

    Angenommen, Sie wollten verwenden forEach auf einen Nodeist es childNodes Eigentum. Du würdest das tun:

    Array.prototype.forEach.call(node.childNodes, function(child) {
        // Do something with `child`
    });
    

    Wenn Sie das häufig tun, sollten Sie eine Kopie der Funktionsreferenz zur Wiederverwendung in eine Variable aufnehmen, z.

    // (This is all presumably in some scoping function)
    var forEach = Array.prototype.forEach;
    
    // Then later...
    forEach.call(node.childNodes, function(child) {
        // Do something with `child`
    });
    
  2. Verwenden Sie ein einfaches for Schleife

    Offensichtlich, ein einfaches for Schleife gilt für Array-ähnliche Objekte.

  3. Benutzen for-in  korrekt

    for-in mit den gleichen Sicherheitsmaßnahmen wie mit einem Array sollte auch mit Array-artigen Objekten arbeiten; Der Vorbehalt für von Host bereitgestellte Objekte auf Nummer 1 kann zutreffen.

  4. Benutzen for-of (verwende einen Iterator implizit) (ES2015 +)

    for-of verwendet den Iterator, der vom Objekt bereitgestellt wird (falls vorhanden); Wir müssen sehen, wie das mit den verschiedenen array-artigen Objekten, insbesondere den vom Host bereitgestellten, spielt. Zum Beispiel die Spezifikation für die NodeList von querySelectorAll wurde aktualisiert, um die Iteration zu unterstützen. Die Spezifikation für die HTMLCollection von getElementsByTagName war nicht.

  5. Verwenden Sie explizit einen Iterator (ES2015 +)

    Siehe # 4, wir müssen sehen, wie Iteratoren ablaufen.

Erstellen Sie ein echtes Array

In anderen Fällen möchten Sie möglicherweise ein Array-ähnliches Objekt in ein echtes Array konvertieren. Das ist überraschend einfach:

  1. Benutze die slice Methode von Arrays

    Wir können das benutzen slice Methode von Arrays, die wie die anderen oben genannten Methoden "absichtlich generisch" sind und daher mit Array-artigen Objekten wie folgt verwendet werden können:

    var trueArray = Array.prototype.slice.call(arrayLikeObject);
    

    Wenn wir zum Beispiel ein NodeList in ein echtes Array könnten wir dies tun:

    var divs = Array.prototype.slice.call(document.querySelectorAll("div"));
    

    Siehe die Vorbehalt für vom Host bereitgestellte Objekte unten. Beachten Sie insbesondere, dass dies in IE8 und früheren Versionen fehlschlägt, in denen Sie die vom Host bereitgestellten Objekte nicht verwenden können this so wie das.

  2. Benutzen Sprungsyntax (...)

    Es ist auch möglich, ES2015 zu verwenden verbreite Syntax mit JavaScript-Engines, die diese Funktion unterstützen:

    var trueArray = [...iterableObject];
    

    Wenn wir zum Beispiel ein NodeList in ein echtes Array, mit Spread-Syntax wird das ziemlich prägnant:

    var divs = [...document.querySelectorAll("div")];
    
  3. Benutzen Array.from  (Spezifikation) | (MDN)

    Array.from (ES2015 +, aber leicht polyfiled) erstellt ein Array aus einem Array-artigen Objekt und übergibt die Einträge optional zuerst durch eine Mapping-Funktion. Damit:

    var divs = Array.from(document.querySelectorAll("div"));
    

    Oder wenn Sie ein Array der Tag-Namen der Elemente mit einer bestimmten Klasse erhalten möchten, verwenden Sie die Mapping-Funktion:

    // Arrow function (ES2015):
    var divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName);
    
    // Standard function (since `Array.from` can be shimmed):
    var divs = Array.from(document.querySelectorAll(".some-class"), function(element) {
        return element.tagName;
    });
    

Vorbehalt für vom Host bereitgestellte Objekte

Wenn du benutzt Array.prototype funktioniert mit Host bereitgestellt Array-ähnliche Objekte (DOM-Listen und andere Dinge, die vom Browser und nicht von der JavaScript-Engine bereitgestellt werden), müssen Sie sicherstellen, dass Sie in Ihren Zielumgebungen testen, ob das vom Host bereitgestellte Objekt ordnungsgemäß funktioniert. Die meisten verhalten sich richtig (Jetzt), aber es ist wichtig zu testen. Der Grund ist, dass die meisten Array.prototype Methoden, die Sie wahrscheinlich verwenden möchten, verlassen sich auf das vom Host bereitgestellte Objekt und geben eine ehrliche Antwort auf das Abstract [[HasProperty]] Betrieb. Während dies geschrieben wird, machen Browser eine sehr gute Arbeit, aber die 5.1-Spezifikation erlaubte die Möglichkeit, dass ein von einem Host bereitgestelltes Objekt möglicherweise nicht ehrlich ist. Es ist in §8.6.2, einige Absätze unter dem großen Tisch am Anfang dieses Abschnitts), wo es heißt:

Host-Objekte können diese internen Methoden in beliebiger Weise implementieren, sofern nicht anders angegeben; Zum Beispiel ist eine Möglichkeit das [[Get]] und [[Put]] für ein bestimmtes Host-Objekt in der Tat holen und speichern Eigenschaftswerte aber [[HasProperty]] erzeugt immer falsch.

(Ich konnte in der ES2015-Spezifikation nicht das entsprechende Wort finden, aber es wird wohl immer noch der Fall sein.) Noch einmal, während wir die üblichen vom Host bereitgestellten Array-artigen Objekte in modernen Browsern schreiben [NodeList Instanzen zum Beispiel] machen Griff [[HasProperty]] richtig, aber es ist wichtig zu testen.)


5976
2018-02-17 13:53



Bearbeiten: Diese Antwort ist hoffnungslos veraltet. Für einen moderneren Ansatz, schau dir das an die für ein Array verfügbaren Methoden. Methoden von Interesse könnten sein:

  • für jede
  • Karte
  • Filter
  • Postleitzahl
  • reduzieren
  • jeden
  • etwas

Die Standardmethode zum Iterieren eines Arrays in JavaScript ist eine Vanille for-Schleife:

var length = arr.length,
    element = null;
for (var i = 0; i < length; i++) {
  element = arr[i];
  // Do something with element i.
}

Beachten Sie jedoch, dass dieser Ansatz nur dann sinnvoll ist, wenn Sie über ein dichtes Array verfügen und jeder Index von einem Element belegt ist. Wenn das Array spärlich ist, kann es bei diesem Ansatz zu Performance-Problemen kommen, da Sie über viele Indizes iterieren, die dies nicht tun Ja wirklich im Array vorhanden. In diesem Fall a for .. in-loop könnte eine bessere Idee sein. jedochSie müssen die entsprechenden Sicherheitsvorkehrungen treffen, um sicherzustellen, dass nur die gewünschten Eigenschaften des Arrays (dh die Array - Elemente) berücksichtigt werden, da der for..in-loop wird auch in älteren Browsern aufgelistet, oder wenn die zusätzlichen Eigenschaften als definiert sind enumerable.

Im ECMAScript 5 Es wird eine ForEach-Methode für den Array-Prototyp geben, die jedoch in älteren Browsern nicht unterstützt wird. Um es konsistent verwenden zu können, müssen Sie entweder über eine Umgebung verfügen, die es unterstützt (z. B. Node.js für serverseitiges JavaScript), oder verwenden Sie ein "Polyfill". Der Polyfill für diese Funktionalität ist jedoch trivial und da es den Code leichter lesbar macht, ist es ein guter Polyfill zu enthalten.


451
2018-02-17 13:55



Wenn du das benutzt jQuery Bibliothek, die Sie verwenden können jQuery.each:

$.each(yourArray, function(index, value) {
  // do your stuff here
});

EDIT: 

Wie pro Frage möchte der Benutzer Code in Javascript anstelle von jquery, so dass die Bearbeitung ist

var length = yourArray.length;   
for (var i = 0; i < length; i++) {
  // Do something with yourArray[i].
}

205
2018-02-17 14:01



Schleife rückwärts

Ich denke der umkehren for-Schleife verdient hier eine Erwähnung:

for (var i = array.length; i--; ) {
     // process array[i]
}

Vorteile:

  • Sie brauchen kein temporäres zu deklarieren len Variable, oder vergleichen Sie gegen array.length bei jeder Iteration, von denen jede eine winzige Optimierung sein könnte.
  • Geschwister entfernen aus dem DOM ist in der Regel in umgekehrter Reihenfolge effizienter. (Der Browser muss weniger Elemente in seinen internen Arrays verschieben.)
  • Wenn du Modifizieren Sie das Array während der Schleife, bei oder nach dem Index ich (Sie entfernen oder fügen zum Beispiel ein Element bei array[i]), dann würde eine Vorwärtsschleife das Element überspringen, das nach links in Position verschoben wurde ichoder neu verarbeiten ichDer Punkt, der nach rechts verschoben wurde. In einer traditionellen for-Schleife, Sie könnte aktualisieren ich um auf das nächste Element zu zeigen, das verarbeitet werden muss - 1, aber einfach die Richtung der Iteration umzukehren, ist oft a einfacher und elegantere Lösung.
  • Ähnlich beim Ändern oder Entfernen verschachtelt DOM-Elemente, Verarbeitung in umgekehrter Reihenfolge Fehler umgehen. Angenommen, Sie können die InnerHTML eines übergeordneten Knotens ändern, bevor Sie die untergeordneten Knoten behandeln. Zu dem Zeitpunkt, zu dem der untergeordnete Knoten erreicht wird, wird er vom DOM getrennt, da er durch ein neu erstelltes untergeordnetes Element ersetzt wurde, als das innereHTML des Parents geschrieben wurde.
  • Es ist kürzer tippen und lesen, als einige der anderen verfügbaren Optionen. Obwohl es verliert forEach() und zu ES6's for ... of.

Nachteile:

  • Es verarbeitet die Artikel in umgekehrter Reihenfolge. Wenn Sie ein neues Array aus den Ergebnissen erstellen oder die Dinge auf dem Bildschirm drucken, natürlich Die Ausgabe wird umgekehrt in Bezug auf die ursprüngliche Reihenfolge.
  • Wiederholtes Einfügen von Geschwistern in das DOM als erstes Kind, um die Reihenfolge beizubehalten weniger effizient. (Der Browser müsste die Dinge immer wieder korrigieren.) Um DOM-Knoten effizient und in der richtigen Reihenfolge zu erstellen, führen Sie einfach eine Schleife vorwärts und hängen Sie sie wie gewohnt an (und verwenden Sie auch ein "Dokumentfragment").
  • Die umgekehrte Schleife ist verwirrend für Junior-Entwickler. (Sie können das als Vorteil erachten, abhängig von Ihrer Einstellung.)

Soll ich es immer benutzen?

Einige Entwickler verwenden die umgekehrte Schleife standardmäßig, es sei denn, es gibt einen guten Grund für die Weiterleitung.

Obwohl die Leistungsgewinne normalerweise unbedeutend sind, schreit es irgendwie:

"Tun Sie das für jeden Punkt in der Liste, mir ist der Auftrag egal!"

In der Praxis ist dies jedoch der Fall nicht eigentlich eine verlässliche Angabe der Absicht, da sie von jenen Anlässen, in denen Sie sich befinden, nicht zu unterscheiden ist machen kümmern sich um die Reihenfolge, und wirklich brauchen rückwärts kreisen. In der Tat wäre ein anderes Konstrukt erforderlich, um die Absicht, etwas nicht zu tun, genau auszudrücken, etwas, das zur Zeit in den meisten Sprachen, einschließlich ECMAScript, nicht verfügbar ist, aber zum Beispiel aufgerufen werden könnte. forEachUnordered().

Wenn die Reihenfolge keine Rolle spielt, und Effizienz ist ein Problem (in der innersten Schleife einer Spiel- oder Animations-Engine), dann kann es akzeptabel sein, die umgekehrte Schleife als Ihr Go-to-Muster zu verwenden. Denken Sie daran, dass Sie eine Umkehrung für die Schleife im vorhandenen Code sehen bedeutet nicht unbedingt dass die Reihenfolge irrelevant ist!

Es ist besser forEach () zu verwenden

Im Allgemeinen für höheren Code wo Klarheit und Sicherheit sind größere Bedenken, würde ich empfehlen, zu verwenden Array::forEach als dein Standardmuster:

  • Es ist klar zu lesen.
  • Es zeigt das an ich wird nicht innerhalb des Blocks verschoben (was immer eine mögliche Überraschung ist, die sich lange versteckt) for und while Schleifen.)
  • Es gibt Ihnen einen Freiraum für Schließungen.
  • Es reduziert die Leckage von lokalen Variablen und zufällige Kollision mit (und Mutation von) äußeren Variablen.

Wenn Sie in Ihrem Code die umgekehrte Schleife sehen, ist das ein Hinweis darauf, dass es aus einem guten Grund umgekehrt wird (vielleicht einer der oben beschriebenen Gründe). Und wenn man eine traditionelle Forward-For-Schleife sieht, kann dies bedeuten, dass eine Verschiebung stattfinden kann.

(Wenn die Diskussion über die Absicht für Sie keinen Sinn ergibt, können Sie und Ihr Code von Crockfords Vortrag profitieren Programmierstil & dein Gehirn.)


Wie funktioniert es?

for (var i = 0; i < array.length; i++) { ... }   // Forwards

for (var i = array.length; i--; )    { ... }   // Reverse

Sie werden das bemerken i-- ist der mittlere Abschnitt (wo wir normalerweise einen Vergleich sehen) und der letzte Satz ist leer (wo wir normalerweise sehen i++). Das bedeutet, dass i-- wird auch als verwendet Bedingung für die Fortsetzung. Entscheidend ist, dass es ausgeführt und überprüft wird Vor jede Iteration.

  • Wie kann es anfangen? array.length ohne zu explodieren?

    weil i-- läuft Vor Bei jeder Iteration greifen wir bei der ersten Iteration tatsächlich auf das Element bei array.length - 1 was vermeidet Probleme mit Array-Out-of-Grenzen  undefined Artikel.

  • Warum hört es nicht auf, vor Index 0 zu iterieren?

    Die Schleife hört auf, wenn die Bedingung durchlaufen wird i-- wird zu einem falschen Wert ausgewertet (wenn es 0 ergibt).

    Der Trick ist, dass anders --idas Nachlaufende i-- Operator dekrementiert i aber ergibt den Wert Vor das Dekrement. Ihre Konsole kann dies demonstrieren:

    > var i = 5; [i, i--, i];

    [5, 5, 4]

    Also auf der letzten Iteration, ich war vorher 1 und das i-- Ausdruck ändert es zu 0 aber ergibt tatsächlich 1 (truthy), und so vergeht der Zustand. Auf der nächsten Iteration i-- Änderungen ich zu -1 aber Erträge 0 (falsch), wodurch die Ausführung sofort aus dem unteren Teil der Schleife herausfällt.

    In der traditionellen Forward for-Schleife, i++ und ++i sind austauschbar (wie Douglas Crockford hervorhebt). Aber im umgekehrten Fall für die Schleife, weil unser Dekrement auch unser Konditionsausdruck ist, müssen wir dabei bleiben i-- wenn wir den Artikel bei Index 0 verarbeiten wollen.


Wissenswertes

Manche Leute zeichnen gerne einen kleinen Pfeil auf der Rückseite for Schleife, und enden mit einem Augenzwinkern:

for (var i = array.length; i --> 0 ;) {

Credits gehen an WYL, weil sie mir die Vorteile und Schrecken der umgekehrten Schleife gezeigt haben.


88
2018-05-02 14:21



Etwas C-Stil Sprachen verwenden foreach Durchlaufen von Aufzählungen. In JavaScript geschieht dies mit dem for..in Schleifenstruktur:

var index,
    value;
for (index in obj) {
    value = obj[index];
}

Es gibt einen Haken. for..in Durchläuft jedes der aufzählbaren Elemente des Objekts und die Elemente seines Prototyps. Um zu vermeiden, dass Werte gelesen werden, die durch den Prototyp des Objekts vererbt werden, überprüfen Sie einfach, ob die Eigenschaft zu dem Objekt gehört:

for (i in obj) {
    if (obj.hasOwnProperty(i)) {
        //do stuff
    }
}

Zusätzlich, ECMAScript 5 hat hinzugefügt forEach Methode zu Array.prototypeMit dieser Option können Sie ein Array mithilfe eines Calbacks aufzählen (das Polyfill befindet sich in den Dokumenten, sodass Sie es immer noch für ältere Browser verwenden können):

arr.forEach(function (val, index, theArray) {
    //do stuff
});

Es ist wichtig das zu beachten Array.prototype.forEach bricht nicht ab, wenn der Callback zurückkehrt false. jQuery und Underscore.js bieten ihre eigenen Variationen an each um Schleifen bereitzustellen, die kurzgeschlossen werden können.


71
2018-02-17 14:00



Wenn Sie ein Array überschleifen möchten, verwenden Sie den Standard-Dreiteiler for Schleife.

for (var i = 0; i < myArray.length; i++) {
    var arrayItem = myArray[i];
}

Sie können durch Caching Performance-Optimierungen erzielen myArray.length oder es rückwärts durchlaufen.


30
2018-02-17 13:55



EIN für jede Implementierung (siehe in jsFiddle):

function forEach(list,callback) {
  var length = list.length;
  for (var n = 0; n < length; n++) {
    callback.call(list[n]);
  }
}

var myArray = ['hello','world'];

forEach(
  myArray,
  function(){
    alert(this); // do something
  }
);

25
2018-04-10 00:26



Wenn es Ihnen nichts ausmacht, das Array zu leeren:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

x enthält den letzten Wert von y und es wird aus dem Array entfernt. Sie können auch verwenden shift() welches den ersten Gegenstand geben und entfernen wird y.


25
2018-03-10 02:37



Ich weiß, das ist ein alter Post, und es gibt schon so viele großartige Antworten. Für etwas mehr Vollständigkeit dachte ich, dass ich einen anderen mit einwerfen würde AngularJS. Das gilt natürlich nur, wenn Sie Angular verwenden, natürlich, trotzdem möchte ich es trotzdem sagen.

angular.forEach benötigt 2 Argumente und ein optionales drittes Argument. Das erste Argument ist das zu iterierende Objekt (Array), das zweite Argument ist die Iterator-Funktion und das optionale dritte Argument ist der Objektkontext (im Grunde genommen innerhalb der Schleife als 'this' bezeichnet).

Es gibt verschiedene Möglichkeiten, die forEach-Schleife von angular zu verwenden. Das einfachste und wahrscheinlich am meisten verwendete ist

var temp = [1, 2, 3];
angular.forEach(temp, function(item) {
    //item will be each element in the array
    //do something
});

Ein anderer Weg, der zum Kopieren von Elementen von einem Array zu einem anderen nützlich ist, ist

var temp = [1, 2, 3];
var temp2 = [];
angular.forEach(temp, function(item) {
    this.push(item); //"this" refers to the array passed into the optional third parameter so, in this case, temp2.
}, temp2);

Obwohl Sie das nicht tun müssen, können Sie einfach Folgendes tun und es entspricht dem vorherigen Beispiel:

angular.forEach(temp, function(item) {
    temp2.push(item);
});

Jetzt gibt es Vor- und Nachteile der Verwendung der angular.forEach Funktion im Gegensatz zu dem eingebauten Vanillegeschmack for Schleife.

Pros

  • Einfache Lesbarkeit
  • Einfache Beschreibbarkeit
  • Wenn verfügbar, angular.forEach wird die ES5 forEach-Schleife verwenden. Jetzt werde ich in der Cons-Sektion effizient arbeiten, wie die forEach-Loops sind viel langsamer als die for-Schleifen. Ich erwähne das als Profi, weil es schön ist, konsistent und standardisiert zu sein.

Betrachten Sie die folgenden 2 verschachtelten Schleifen, die genau dasselbe tun. Nehmen wir an, wir haben 2 Arrays von Objekten und jedes Objekt enthält ein Array von Ergebnissen, von denen jedes eine Value-Eigenschaft hat, die eine Zeichenfolge (oder was auch immer) ist. Und sagen wir, wir müssen über jedes der Ergebnisse iterieren, und wenn sie gleich sind, dann führe eine Aktion aus:

angular.forEach(obj1.results, function(result1) {
    angular.forEach(obj2.results, function(result2) {
        if (result1.Value === result2.Value) {
            //do something
        }
    });
});

//exact same with a for loop
for (var i = 0; i < obj1.results.length; i++) {
    for (var j = 0; j < obj2.results.length; j++) {
        if (obj1.results[i].Value === obj2.results[j].Value) {
            //do something
        }
    }
}

Zugegeben, dies ist ein sehr einfaches hypothetisches Beispiel, aber ich habe Triple Embedded für Schleifen mit dem zweiten Ansatz geschrieben und es war sehr schwer zu lesen, und schreiben Sie für diese Angelegenheit.

Nachteile

  • Effizienz. angular.forEachund der Eingeborene forEachfür beides sind beide so sehr langsamer als normal for Schleife .... ungefähr 90% langsamer. Also für große Datensätze, am besten, um das native zu bleiben for Schleife.
  • Kein Brechen, fortfahren oder Support zurückgeben. continue wird tatsächlich unterstützt von "Unfall", um in einem fortzusetzen angular.forEach Du stellst einfach ein return; Aussage in der Funktion wie angular.forEach(array, function(item) { if (someConditionIsTrue) return; }); Dadurch wird die Funktion für diese Iteration nicht fortgesetzt. Dies liegt auch an der Tatsache, dass der Eingeborene forEach unterstützt nicht brechen oder fortfahren.

Ich bin mir sicher, dass es auch verschiedene andere Vor- und Nachteile gibt, und bitte fügen Sie alles hinzu, was Sie für richtig halten. Ich fühle, dass, unter dem Strich, wenn Sie Effizienz brauchen, nur mit dem nativen bleiben for Schleife für Ihre Looping-Bedürfnisse. Aber wenn Ihre Datensätze kleiner sind und eine gewisse Effizienz ausreicht, um im Austausch für Lesbarkeit und Schreibbarkeit aufzugeben, werfen Sie auf jeden Fall ein angular.forEach in diesem bösen Jungen.


25
2018-06-20 22:56



Eine einfache Lösung wäre jetzt die Verwendung der underscore.js-Bibliothek. Es bietet viele nützliche Werkzeuge, wie z each und wird den Job automatisch an den Nativen delegieren forEach wenn verfügbar.

Ein CodePen-Beispiel wie es funktioniert ist:

var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});

Siehe auch


24
2017-07-17 09:07