Für jeden über ein Array in JavaScript


4683

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

Ich dachte, es wäre so etwas:

forEach(instance in theArray)

Wo theArrayist mein Array, aber das scheint falsch zu sein.


16
Ich habe danach gesucht, aber ich habe gesucht forEach und nicht nur for. wie gesagt, in c # war es ein bisschen anders, und das hat mich verwirrt :)
Dante1986

6
ECMAScript 6 enthält möglicherweise das Konstrukt "for ... of". Siehe für ... von (MDN) für weitere Informationen. Sie können es bereits mit den neuesten Firefox-Versionen ausprobieren.
Slaven Rezic

36
Array.ForEach ist für Arrays in JavaScript etwa 95% langsamer als for () in. Sehen Sie diesen Leistungstest online: jsperf.com/fast-array-foreach via coderwall.com/p/kvzbpa
molokoloco

77
In vielen Situationen wird 95% langsamer nicht signifikant sein blog.niftysnippets.org/2012/02/foreach-and-runtime-cost.html
David Sykes

7
Im Gegensatz dazu in Python ist es effiziente Funktionen zu verwenden , als zu verwenden traditioneller for - Schleifen. ( Man bedenke , dass i < lenund i++kann durch den Motor durchgeführt werden, anstatt durch den Interpreter.)
joeytwiddle

Antworten:


7021

TL; DR

  • Verwenden for-inSie es nur, wenn Sie es mit Schutzmaßnahmen verwenden oder zumindest wissen, warum es Sie beißen könnte.
  • Ihre besten Wetten sind normalerweise

    • eine for-ofSchleife (nur ES2015 +),
    • Array#forEach( spec| MDN) (oder seine Verwandten someund dergleichen) (nur ES5 +),
    • eine einfache altmodische forSchleife,
    • oder for-inmit Schutzmaßnahmen.

Aber es gibt noch viel mehr zu entdecken, weiterzulesen ...


JavaScript verfügt über eine leistungsstarke Semantik zum Durchlaufen von Arrays und Array-ähnlichen Objekten. Ich habe die Antwort in zwei Teile geteilt: Optionen für echte Arrays und Optionen für Dinge, die nur Array- ähnlich sind , wie das argumentsObjekt, andere iterierbare Objekte (ES2015 +), DOM-Sammlungen und so weiter.

Ich werde schnell beachten Sie, dass Sie die ES2015 - Optionen können nun auch auf ES5 - Motoren, von transpiling ES2015 bis ES5. Suchen Sie nach "ES2015 transpiling" / "ES6 transpiling" für mehr ...

Okay, schauen wir uns unsere Optionen an:

Für tatsächliche Arrays

Sie haben drei Optionen in ECMAScript 5 ("ES5"), der derzeit am weitesten verbreiteten Version, und zwei weitere in ECMAScript 2015 ("ES2015", "ES6"):

  1. Verwendung forEachund verwandte (ES5 +)
  2. Verwenden Sie eine einfache forSchleife
  3. verwenden Sie for-in richtig
  4. Verwenden for-of(implizit einen Iterator verwenden) (ES2015 +)
  5. Verwenden Sie explizit einen Iterator (ES2015 +)

Einzelheiten:

1. Verwenden forEachund verwandt

In jeder vage modernen Umgebung (also nicht in IE8), in der Sie Zugriff auf die Arrayvon ES5 hinzugefügten Funktionen haben (direkt oder mithilfe von Polyfills), können Sie forEach( spec| MDN) verwenden:

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

forEachAkzeptiert eine Rückruffunktion und optional einen Wert, der thisbeim Aufrufen dieses Rückrufs verwendet werden soll (oben nicht verwendet). Der Rückruf wird für jeden Eintrag im Array aufgerufen, um nicht vorhandene Einträge in dünn besetzten Arrays zu überspringen. Obwohl ich oben nur ein Argument verwendet habe, wird der Rückruf mit drei aufgerufen: Der Wert jedes Eintrags, der Index dieses Eintrags und ein Verweis auf das Array, über das Sie iterieren (falls Ihre Funktion es noch nicht zur Hand hat ).

Sofern Sie nicht veraltete Browser wie IE8 unterstützen (NetApps weist zum Zeitpunkt dieses Schreibens im September 2016 einen Marktanteil von etwas mehr als 4% auf), können Sie diese forEachproblemlos auf einer Allzweck-Webseite ohne Shim verwenden. Wenn Sie veraltete Browser unterstützen müssen, ist das Shimmen / Polyfilling forEacheinfach (suchen Sie nach "es5 shim" für mehrere Optionen).

forEach hat den Vorteil, dass Sie keine Indexierungs- und Wertvariablen im enthaltenen Bereich deklarieren müssen, da sie als Argumente für die Iterationsfunktion bereitgestellt werden und sich so gut auf diese Iteration beschränken.

Wenn Sie sich Sorgen über die Laufzeitkosten für einen Funktionsaufruf für jeden Array-Eintrag machen, sollten Sie dies nicht tun. Details .

Darüber hinaus gibt forEaches die Funktion "Schleife durch alle", aber ES5 hat mehrere andere nützliche Funktionen definiert, mit denen Sie sich durch das Array arbeiten und Dinge erledigen können, darunter:

  • every(stoppt die Schleife, wenn der Rückruf zum ersten Mal zurückkehrt falseoder etwas Falsches)
  • some(stoppt die Schleife, wenn der Rückruf zum ersten Mal zurückkehrt trueoder etwas Wahres)
  • filter(Erstellt ein neues Array mit Elementen, bei denen die Filterfunktion zurückgegeben wird, trueund lässt diejenigen weg, bei denen sie zurückgegeben wird. false)
  • map (Erstellt ein neues Array aus den vom Rückruf zurückgegebenen Werten.)
  • reduce (Baut einen Wert auf, indem der Rückruf wiederholt aufgerufen wird und vorherige Werte übergeben werden. Einzelheiten finden Sie in der Spezifikation. Nützlich zum Summieren des Inhalts eines Arrays und vieler anderer Dinge.)
  • reduceRight(wie reduce, funktioniert aber eher in absteigender als in aufsteigender Reihenfolge)

2. Verwenden Sie eine einfache forSchleife

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 die Länge des Feldes wird nicht während der Schleife ändern, und es ist in leistungskritischen Code (unwahrscheinlich), eine etwas kompliziertere Version die Länge vorne greifen könnte ein seine winzig bisschen 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]);
}

Bei modernen JavaScript-Engines ist es jedoch selten, dass Sie das letzte Stück Saft herausholen müssen.

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

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

Und wenn Sie dies tun, wird nicht nur, valuesondern auch indexfür jede Schleifeniteration neu erstellt, was bedeutet, dass im Schleifenkörper erstellte Abschlüsse einen Verweis auf das index(und value) enthalten, das für diese bestimmte Iteration erstellt wurde:

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

Wenn Sie fünf Divs hatten, erhalten Sie "Index ist: 0", wenn Sie auf den ersten geklickt haben, und "Index ist: 4", wenn Sie auf den letzten geklickt haben. Dies funktioniert nicht , wenn Sie varanstelle von verwenden let.

3. for-in Richtig verwenden

Sie erhalten die Menschen sagen , die Sie zu verwenden for-in, aber das ist nicht das, was for-infür ist . for-inDurchläuft die aufzählbaren Eigenschaften eines Objekts und nicht die Indizes eines Arrays. Die Bestellung ist nicht garantiert , auch nicht in ES2015 (ES6). ES2015 + definiert zwar eine Reihenfolge für Objekteigenschaften (via [[OwnPropertyKeys]], [[Enumerate]]und Dinge, die sie verwenden Object.getOwnPropertyKeys), aber es wurde nicht definiert, for-inwelche Reihenfolge dieser Reihenfolge folgen würde. ES2020 hat es jedoch getan. (Details in dieser anderen Antwort .)

Die einzigen realen Anwendungsfälle für for-inein Array sind:

  • Es ist eine spärliche Anordnung mit massiven Lücken, oder
  • Sie verwenden Nicht-Elementeigenschaften und möchten diese in die Schleife aufnehmen

Betrachten Sie nur das erste Beispiel: Sie können for-indiese spärlichen Array-Elemente verwenden, wenn Sie geeignete 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 checks are
        /^0$|^[1-9]\d*$/.test(key) &&    // explained
        key <= 4294967294                // below
        ) {
        console.log(a[key]);
    }
}

Beachten Sie die drei Prüfungen:

  1. Dass das Objekt eine eigene Eigenschaft mit diesem Namen hat (keine, die es von seinem Prototyp erbt), und

  2. Dass der Schlüssel alle Dezimalstellen sind (z. B. normale Zeichenfolgenform, keine wissenschaftliche Notation), und

  3. Dass der Wert des Schlüssels, wenn er zu einer Zahl gezwungen wird, <= 2 ^ 32 - 2 ist (was 4,294,967,294 ist). Woher kommt diese Nummer? Es ist Teil der Definition eines Array-Index in der Spezifikation . Andere Zahlen (Nicht-Ganzzahlen, negative Zahlen, Zahlen größer als 2 ^ 32 - 2) sind keine Array-Indizes. Der Grund, warum es 2 ^ 32 - 2 ist, ist, dass dadurch der größte Indexwert niedriger als 2 ^ 32 - 1 wird , was der maximale Wert ist, den ein Array haben lengthkann. (ZB passt die Länge eines Arrays in eine 32-Bit-Ganzzahl ohne Vorzeichen.) (Wir bitten RobG, in einem Kommentar in meinem Blog-Beitrag darauf hinzuweisen, dass mein vorheriger Test nicht ganz richtig war.)

Das würden Sie natürlich nicht im Inline-Code tun. Sie würden eine Dienstprogrammfunktion schreiben. Vielleicht:

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

ES2015 fügte Iteratoren zu JavaScript hinzu. Der einfachste Weg, Iteratoren zu verwenden, ist die neue for-ofAnweisung. Es sieht aus wie das:

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

Unter der Decke erhält das einen Iterator aus dem Array und durchläuft es, wobei die Werte daraus abgerufen werden. Dies hat nicht das Problem, das bei der Verwendung for-inauftritt, da ein vom Objekt (dem Array) definierter Iterator verwendet wird und Arrays definieren, dass ihre Iteratoren ihre Einträge (nicht ihre Eigenschaften) durchlaufen . Anders als for-inin 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 möglicherweise einen Iterator explizit verwenden . Sie können das auch tun, obwohl es viel klobiger ist als for-of. Es sieht aus wie das:

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

Der Iterator ist ein Objekt, das mit der Iteratordefinition in der Spezifikation übereinstimmt. Die nextMethode gibt bei jedem Aufruf ein neues Ergebnisobjekt zurück . Das Ergebnisobjekt hat eine Eigenschaft, donedie uns mitteilt, ob es fertig ist, und eine Eigenschaft valuemit dem Wert für diese Iteration. ( doneist optional, wenn es wäre false, valueist optional, wenn es wäre undefined.)

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

  • values(): Dies ist die, die ich oben verwendet habe. Es gibt einen Iterator , wobei jedes valueder Array - Eintrag für diese Iteration ( "a", "b", und "c"in dem Beispiel weiter oben).
  • keys(): Gibt einen Iterator zurück, wobei jeder valueder Schlüssel für diese Iteration ist (für unsere aobigen wäre das also "0"dann "1", dann "2").
  • entries(): Gibt einen Iterator zurück, wobei jedes valueein Array im Formular [key, value]für diese Iteration ist.

Für Array-ähnliche Objekte

Abgesehen von echten Arrays gibt es auch Array-ähnliche Objekte, die eine lengthEigenschaft und Eigenschaften mit numerischen Namen haben: NodeListInstanzen, das argumentsObjekt usw. Wie durchlaufen wir ihren Inhalt?

Verwenden Sie eine der oben genannten Optionen für Arrays

Zumindest einige und möglicherweise die meisten oder sogar alle der oben genannten Array-Ansätze gelten häufig gleich gut für Array-ähnliche Objekte:

  1. Verwendung forEachund verwandte (ES5 +)

    Die verschiedenen Funktionen Array.prototypesind "absichtlich generisch" und können normalerweise für Array-ähnliche Objekte über Function#calloder verwendet werden Function#apply. (Siehe die Einschränkung für vom Host bereitgestellte Objekte am Ende dieser Antwort, aber es ist ein seltenes Problem.)

    Angenommen , Sie verwenden wollten forEachauf einem Node‚s - childNodesEigenschaft. Du würdest das tun:

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

    Wenn Sie dies häufig tun, möchten Sie möglicherweise 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 eine einfache forSchleife

    Offensichtlich gilt eine einfache forSchleife für Array-ähnliche Objekte.

  3. verwenden Sie for-in richtig

    for-inmit den gleichen Sicherheitsvorkehrungen wie mit einem Array sollte auch mit Array-ähnlichen Objekten funktionieren; Möglicherweise gilt die Einschränkung für vom Host bereitgestellte Objekte unter Nummer 1 oben.

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

    for-ofverwendet den vom Objekt bereitgestellten Iterator (falls vorhanden). Dies schließt vom Host bereitgestellte Objekte ein. Beispielsweise wurde die Spezifikation für das NodeListvon querySelectorAllaktualisiert, um die Iteration zu unterstützen. Die Spezifikation für das HTMLCollectionvon getElementsByTagNamewar nicht.

  5. Verwenden Sie explizit einen Iterator (ES2015 +)

    Siehe # 4.

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. Verwenden Sie die sliceMethode der Arrays

    Wir können die sliceMethode von Arrays verwenden, die wie die anderen oben genannten Methoden "absichtlich generisch" ist und daher mit Array-ähnlichen Objekten wie diesen verwendet werden kann:

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

    Wenn wir beispielsweise a NodeListin ein echtes Array konvertieren möchten , können wir Folgendes tun:

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

    Weitere Informationen zu vom Host bereitgestellten Objekten finden Sie weiter unten. Beachten Sie insbesondere, dass dies in IE8 und früheren Versionen fehlschlägt, sodass Sie vom Host bereitgestellte Objekte nicht so verwenden können this.

  2. Verwenden Sie die Spread-Syntax ( ...)

    Es ist auch möglich, die Spread-Syntax von ES2015 mit JavaScript-Engines zu verwenden, die diese Funktion unterstützen. Wie for-ofdies den verwendet Iterator vom Objekt zur Verfügung gestellt (siehe # 4 im vorherigen Abschnitt):

    var trueArray = [...iterableObject];

    Wenn wir zum Beispiel a NodeListin ein echtes Array konvertieren möchten , wird dies mit der Spread-Syntax ziemlich prägnant:

    var divs = [...document.querySelectorAll("div")];
  3. Verwenden Array.from

    Array.from (spec) | (MDN) (ES2015 +, aber leicht polyfüllbar) erstellt ein Array aus einem Array-ähnlichen Objekt, wobei die Einträge optional zuerst über eine Zuordnungsfunktion übergeben werden. Damit:

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

    Wenn Sie ein Array der Tag-Namen der Elemente mit einer bestimmten Klasse abrufen möchten, verwenden Sie die Zuordnungsfunktion:

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

Vorsichtsmaßnahme für vom Host bereitgestellte Objekte

Wenn Sie Array.prototypeFunktionen mit vom Host bereitgestellten Array-ähnlichen Objekten verwenden (DOM-Listen und andere vom Browser anstelle der JavaScript-Engine bereitgestellte Dinge), müssen Sie sicherstellen, dass Sie in Ihren Zielumgebungen testen, um sicherzustellen, dass sich das vom Host bereitgestellte Objekt ordnungsgemäß verhält . Die meisten verhalten sich (jetzt) richtig , aber es ist wichtig zu testen. Der Grund dafür ist, dass die meisten Array.prototypeMethoden, die Sie wahrscheinlich verwenden möchten, auf dem vom Host bereitgestellten Objekt basieren, das eine ehrliche Antwort auf die abstrakte [[HasProperty]]Operation gibt. Zum jetzigen Zeitpunkt leisten Browser sehr gute Arbeit, aber die 5.1-Spezifikation hat die Möglichkeit berücksichtigt, dass ein vom Host bereitgestelltes Objekt möglicherweise nicht ehrlich ist. Es ist in §8.6.2 , mehrere Absätze unter der großen Tabelle am Anfang dieses Abschnitts), wo es heißt:

Hostobjekte können diese internen Methoden auf jede Art und Weise implementieren, sofern nicht anders angegeben. zum Beispiel ist eine Möglichkeit , dass , [[Get]]und [[Put]]für ein bestimmtes Host - Objekt in der Tat Abruf- und Speichereigenschaftswerte aber [[HasProperty]]immer erzeugt falsch .

(Ich konnte nicht den äquivalent Wortschwall in der ES2015 - Spezifikation finden, aber es ist gesprungen , der Fall noch sein.) Auch hier, wie dies den gemeinsamen Host-bereitgestellt Schreiben Array-ähnliche Objekte in modernen Browsern [ NodeListInstanzen, zum Beispiel] tun Griffes [[HasProperty]]richtig, aber es ist wichtig zu testen.)


44
Ich möchte auch hinzufügen, dass .forEachnicht effizient gebrochen werden kann. Sie müssen eine Ausnahme auslösen, um die Pause auszuführen.
Pijusn

82
@ Pius: Wenn Sie die Schleife brechen möchten, können Sie verwenden some. (Ich hätte es vorgezogen, auch das Brechen zuzulassen forEach, aber sie haben mich nicht gefragt. ;-))
TJ Crowder

6
@TJCrowder True, obwohl es eher wie eine Problemumgehung aussieht, da es nicht sein Hauptzweck ist.
Pijusn

8
@ user889030: Du brauchst ein ,After k=0, kein ;. Denken Sie daran, Programmierung ist viele Dinge, von denen eines viel Liebe zum Detail ist ... :-)
TJ Crowder

5
@ JimB: Das ist oben behandelt (und lengthist keine Methode). :-)
TJ Crowder

513

Hinweis : Diese Antwort ist hoffnungslos veraltet. Schauen Sie sich für einen moderneren Ansatz die auf einem Array verfügbaren Methoden an . Methoden von Interesse könnten sein:

  • für jedes
  • Karte
  • Filter
  • Postleitzahl
  • reduzieren
  • jeder
  • etwas

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

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

Beachten Sie jedoch, dass dieser Ansatz nur dann gut ist, wenn Sie ein dichtes Array haben und jeder Index von einem Element belegt ist. Wenn das Array spärlich ist, können bei diesem Ansatz Leistungsprobleme auftreten, da Sie viele Indizes durchlaufen, die im Array nicht wirklich vorhanden sind. In diesem Fall for .. inkönnte eine Schleife eine bessere Idee sein. Allerdings müssen Sie die entsprechenden Schutzmaßnahmen verwenden , die nur die gewünschten Eigenschaften des Arrays zu gewährleisten (das heißt, die Array - Elemente) beaufschlagt werden, da die for..in-loop auch in älterem Browser aufgelistet werden, oder wenn die zusätzlichen Eigenschaften sind definiert als enumerable.

In ECMAScript 5 gibt es eine forEach-Methode für den Array-Prototyp, 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 eine "Polyfill" verwenden. Die Polyfüllung für diese Funktionalität ist jedoch trivial und da sie das Lesen des Codes erleichtert, ist sie eine gute Polyfüllung.


2
Warum ist for(instance in objArray) eine korrekte Verwendung nicht? es sieht für mich einfacher aus, aber ich höre, dass Sie davon sprechen, dass es nicht die richtige Art der Verwendung ist?
Dante1986

21
Sie können das Inline-Längen-Caching verwenden: für (var i = 0, l = arr.length; i <l; i ++)
Robert Hoffmann

3
Ist das Komma am Ende der ersten Zeile beabsichtigt oder ist es ein Tippfehler (könnte ein Semikolon sein)?
Mohd Abdul Mujib

6
@ wardha-Web Es ist beabsichtigt. Es ermöglicht uns, mehrere Variablen mit einem einzigen varSchlüsselwort zu deklarieren . Wenn wir ein Semikolon verwendet hätten, elementwäre es im globalen Bereich deklariert worden (oder besser gesagt, JSHint hätte uns angeschrien, bevor es die Produktion erreichte).
PatrikAkerstrand

239

Wenn Sie die jQuery- Bibliothek verwenden, können Sie jQuery.each verwenden :

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

BEARBEITEN:

Gemäß der Frage möchte der Benutzer Code in Javascript anstelle von jquery, so dass die Bearbeitung erfolgt

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

2
Ich werde diese Antwort wahrscheinlich am häufigsten verwenden. Es ist nicht die beste Antwort auf die Frage, aber in der Praxis wird es für diejenigen von uns, die jQuery verwenden, die einfachste und am besten geeignete sein. Ich denke, wir sollten alle auch Vanille lernen. Es tut nie weh, Ihr Verständnis zu erweitern.
Mopsyd

47
Nur um der Sache willen: jQuery ist viel langsamer als native Lösungen. Es wird von jQuery empfohlen, natives JavaScript anstelle von jQuery zu verwenden, wann immer dies möglich ist. jsperf.com/browser-diet-jquery-each-vs-for-loop
Kevin Boss

8
Verwenden Sie jQuery nicht, wenn Sie Vanille js
Noe

2
Halten Sie sich an Standard-JS und halten Sie die Bibliotheken von Drittanbietern von der Antwort
fern,

116

Schleife rückwärts

Ich denke, die Umkehrung der Schleife verdient hier eine Erwähnung:

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

Vorteile:

  • Sie müssen keine temporäre lenVariable deklarieren oder array.lengthbei jeder Iteration vergleichen, was eine winzige Optimierung sein könnte.
  • Das Entfernen von Geschwistern aus dem DOM in umgekehrter Reihenfolge ist normalerweise effizienter . (Der Browser muss weniger Elemente in seinen internen Arrays verschieben.)
  • Wenn Sie das Array während der Schleife am oder nach dem Index i ändern (z. B. wenn Sie ein Element entfernen oder einfügen array[i]), überspringt eine Vorwärtsschleife das Element, das nach links in Position i verschoben wurde , oder verarbeitet das i- te Element erneut nach rechts verschoben. In einem traditionellen for - Schleife, Sie könnten aktualisieren i zum nächsten Punkt zu Punkt , dass Bedürfnisse der Verarbeitung - 1, sondern einfach die Umkehrung der Richtung der Iteration ist oft eine einfachere und elegantere Lösung .
  • In ähnlicher Weise kann die umgekehrte Verarbeitung beim Ändern oder Entfernen verschachtelter DOM-Elemente Fehler umgehen . Ziehen Sie beispielsweise in Betracht, das innerHTML eines übergeordneten Knotens zu ändern, bevor Sie dessen untergeordnete Knoten behandeln. Wenn der untergeordnete Knoten erreicht ist, wird er vom DOM getrennt und durch ein neu erstelltes untergeordnetes Element ersetzt, als das innerHTML des übergeordneten Knotens geschrieben wurde.
  • Es ist kürzer zu tippen und zu lesen als einige der anderen verfügbaren Optionen. Obwohl es gegen forEach()und gegen ES6 verliert for ... of.

Nachteile:

  • Es verarbeitet die Artikel in umgekehrter Reihenfolge. Wenn Sie aus den Ergebnissen ein neues Array erstellt oder Dinge auf dem Bildschirm gedruckt haben, wird die Ausgabe natürlich in Bezug auf die ursprüngliche Reihenfolge umgekehrt .
  • Das wiederholte Einfügen von Geschwistern als erstes Kind in das DOM, um die Reihenfolge beizubehalten, ist weniger effizient . (Der Browser müsste die Dinge immer wieder nach rechts verschieben.) Um DOM-Knoten effizient und in der richtigen Reihenfolge zu erstellen, müssen Sie nur eine Vorwärtsschleife ausführen und wie gewohnt anhängen (und auch ein "Dokumentfragment" verwenden).
  • Die umgekehrte Schleife ist für Nachwuchsentwickler verwirrend . (Abhängig von Ihrem Ausblick können Sie dies als Vorteil betrachten.)

Soll ich es immer benutzen?

Einige Entwickler verwenden standardmäßig die umgekehrte for-Schleife , es sei denn, es gibt einen guten Grund, eine Vorwärtsschleife durchzuführen.

Obwohl die Leistungssteigerungen normalerweise unbedeutend sind, schreit es:

"Mach das einfach mit jedem Artikel in der Liste, mir ist die Bestellung egal!"

In der Praxis ist dies jedoch kein verlässlicher Hinweis auf die Absicht, da es nicht von den Gelegenheiten zu unterscheiden ist, in denen Sie sich um die Reihenfolge kümmern und wirklich eine umgekehrte Schleife durchführen müssen. Tatsächlich wäre also ein anderes Konstrukt erforderlich, um die Absicht "egal" genau auszudrücken, was derzeit in den meisten Sprachen, einschließlich ECMAScript, nicht verfügbar ist, aber beispielsweise aufgerufen werden könnte forEachUnordered().

Wenn die Reihenfolge keine Rolle spielt und die Effizienz ein Problem darstellt (in der innersten Schleife eines Spiels oder einer Animations-Engine), kann es akzeptabel sein, die umgekehrte for-Schleife als Ausgangsmuster zu verwenden. Denken Sie daran, dass eine umgekehrte for-Schleife im vorhandenen Code nicht unbedingt bedeutet, dass die Reihenfolge irrelevant ist!

Es war besser, forEach () zu verwenden

Im Allgemeinen habe ich für Code auf höherer Ebene, bei dem Klarheit und Sicherheit eine größere Array::forEachRolle spielen , zuvor empfohlen, als Standardmuster für Schleifen zu verwenden (obwohl ich heutzutage die Verwendung bevorzuge for..of). Gründe, forEacheine Rückwärtsschleife vorzuziehen , sind:

  • Es ist klarer zu lesen.
  • Es zeigt an, dass ich nicht innerhalb des Blocks verschoben werde (was immer eine mögliche Überraschung ist, die sich in langen forund whileSchleifen versteckt ).
  • Es gibt Ihnen einen freien Spielraum für Schließungen.
  • Es reduziert das Auslaufen lokaler Variablen und die versehentliche Kollision mit (und die Mutation von) äußeren Variablen.

Wenn Sie dann die umgekehrte for-Schleife in Ihrem Code sehen, ist dies ein Hinweis darauf, dass sie aus einem guten Grund umgekehrt ist (möglicherweise einer der oben beschriebenen Gründe). Wenn Sie eine herkömmliche Forward-for-Schleife sehen, kann dies darauf hinweisen, dass eine Verschiebung stattfinden kann.

(Wenn die Diskussion der Absicht für Sie keinen Sinn ergibt, können Sie und Ihr Code davon profitieren, Crockfords Vortrag über Programmierstil und Ihr Gehirn zu sehen .)

Es ist jetzt noch besser für ... zu verwenden!

Es gibt eine Debatte darüber, ob for..ofoder forEach()vorzuziehen sind:

  • Für eine maximale Browserunterstützung ist for..of eine Polyfüllung für Iteratoren erforderlich , wodurch die Ausführung Ihrer App etwas langsamer und das Herunterladen etwas größer wird.

  • Aus diesem Grunde (und Nutzung zu fördern mapund filter,) einig Front-End - Styleguides verbieten for..ofkomplett!

  • Die oben genannten Bedenken gelten jedoch nicht für Node.js-Anwendungen, die for..ofjetzt gut unterstützt werden.

  • Und await funktioniert außerdem nicht im Inneren forEach(). Die Verwendung for..ofist in diesem Fall das klarste Muster .

Persönlich neige ich dazu, das zu verwenden, was am einfachsten zu lesen ist, es sei denn, Leistung oder Minimierung sind zu einem Hauptanliegen geworden. Daher bevorzuge ich heutzutage die Verwendung for..ofanstelle von forEach(), aber ich werde immer mapoder filteroder findoder somewenn zutreffend verwenden. (Für meine Kollegen benutze ich selten reduce.)


Wie funktioniert es?

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

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

Sie werden feststellen, dass dies i--der mittlere Satz ist (wo wir normalerweise einen Vergleich sehen) und der letzte Satz leer ist (wo wir normalerweise sehen i++). Das heißt, das i--wird auch als Voraussetzung für die Fortsetzung verwendet. Entscheidend ist, dass es vor jeder Iteration ausgeführt und überprüft wird.

  • Wie kann es beginnen, array.lengthohne zu explodieren?

    Da i--läuft vor jeder Iteration bei der ersten Iteration werden wir tatsächlich das Element zugreifen bei array.length - 1denen Probleme mit vermeidet Array-out-of-bounds undefined Artikeln.

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

    Die Schleife i--hört auf zu iterieren, wenn die Bedingung einen Falsey-Wert ergibt (wenn sie 0 ergibt).

    Der Trick ist, dass im Gegensatz dazu --ider nachfolgende i--Operator dekrementiert, iaber den Wert vor dem Dekrement liefert . Ihre Konsole kann dies demonstrieren:

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

    [5, 5, 4]

    Bei der letzten Iteration war ich zuvor 1 und der i--Ausdruck ändert ihn in 0 , ergibt aber tatsächlich 1 (wahr), und so besteht die Bedingung. Bei der nächsten Iteration i--ändert sich i auf -1 , ergibt jedoch 0 (Falsey), wodurch die Ausführung sofort aus dem unteren Bereich der Schleife herausfällt.

    In der traditionellen Forwards for-Schleife i++und ++isind austauschbar (wie Douglas Crockford betont). Umgekehrt müssen wir jedoch bei der umgekehrten for-Schleife bleiben, da unser Dekrement auch unser Bedingungsausdruck ist, i--wenn wir das Element bei Index 0 verarbeiten möchten.


Wissenswertes

Einige Leute zeichnen gerne einen kleinen Pfeil in die umgekehrte forSchleife und beenden mit einem Augenzwinkern:

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

Dank geht an WYL, weil er mir die Vorteile und Schrecken der umgekehrten for-Schleife gezeigt hat.


3
Ich habe vergessen, die Benchmarks hinzuzufügen . Ich habe auch vergessen zu erwähnen, dass Reverse Looping eine signifikante Optimierung für 8-Bit-Prozessoren wie den 6502 darstellt, bei denen Sie den Vergleich wirklich kostenlos erhalten!
Joeytwiddle

Die gleiche Antwort ist viel prägnanter gegeben hier (auf einer anderen Frage).
Joeytwiddle

84

Einige Sprachen im C- Stil verwenden foreachzum Durchlaufen von Aufzählungen. In JavaScript erfolgt dies mit der for..inSchleifenstruktur :

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

Es gibt einen Haken. for..indurchläuft jedes der aufzählbaren Elemente des Objekts und die Elemente auf seinem Prototyp. Um zu vermeiden, dass Werte gelesen werden, die vom Prototyp des Objekts geerbt werden, überprüfen Sie einfach, ob die Eigenschaft zum Objekt gehört:

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

Darüber hinaus hat ECMAScript 5 eine forEachMethode hinzugefügt , mit Array.prototypeder ein Array mithilfe eines Calbacks aufgelistet werden kann (die Polyfüllung befindet sich in den Dokumenten, sodass Sie sie weiterhin für ältere Browser verwenden können):

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

Es ist wichtig zu beachten, dass Array.prototype.forEachdies nicht unterbrochen wird, wenn der Rückruf zurückkehrt false. jQuery und Underscore.js bieten ihre eigenen Variationen an each, um Schleifen bereitzustellen, die kurzgeschlossen werden können.


3
Wie kann man also aus einer ECMAScript5-foreach-Schleife ausbrechen, wie wir es für eine normale for-Schleife oder eine foreach-Schleife wie in C-Sprachen tun würden?
Ciaran Gallagher

5
@CiaranG, in JavaScript werden häufig eachMethoden angezeigt, return falsemit denen die Schleife verlassen werden kann. forEachDies ist jedoch keine Option. Ein externes Flag könnte verwendet werden (dh if (flag) return;es würde nur verhindern, dass der Rest des Funktionskörpers ausgeführt wird, und forEachweiterhin über die gesamte Sammlung iterieren.
zzzzBov

43

Wenn Sie ein Array durchlaufen möchten, verwenden Sie die dreiteilige Standardschleife for.

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

Sie können einige Leistungsoptimierungen erzielen, indem Sie sie zwischenspeichern myArray.lengthoder rückwärts durchlaufen.


6
für (var i = 0, Länge = myArray.length; i <Länge; i ++) sollte es tun
Edson Medina

5
@EdsonMedina Dadurch wird auch eine neue globale Variable namens erstellt length. ;)
joeytwiddle

4
@joeytwiddle Ja, aber das würde den Rahmen dieses Beitrags sprengen. Sie werden trotzdem eine globale Variable i erstellen.
Edson Medina

6
@EdsonMedina Ich entschuldige mich, ich hatte das völlig falsch. Wenn Sie ,nach einer Aufgabe verwenden, wird kein neues globales Element eingeführt. Ihr Vorschlag ist also in Ordnung ! Ich habe dies für ein anderes Problem verwirrt: Wenn Sie =nach einer Zuweisung verwenden, wird eine neue globale erstellt.
Joeytwiddle

Beachten Sie, dass die Variable i nicht lokal für die Schleife ist. JavaScript hat keinen Blockbereich. Es ist wahrscheinlich besser, var i, length, arrayItem;vor der Schleife zu deklarieren , um dieses Missverständnis zu vermeiden.
James

35

Ich weiß, dass dies ein alter Beitrag ist, und es gibt bereits so viele gute Antworten. Der Vollständigkeit halber dachte ich, ich würde mit AngularJS einen anderen einwerfen . Dies gilt natürlich nur, wenn Sie Angular verwenden. Trotzdem möchte ich es trotzdem sagen.

angular.forEachNimmt 2 Argumente und ein optionales drittes Argument. Das erste Argument ist das Objekt (Array), über das iteriert werden soll, das zweite Argument ist die Iteratorfunktion und das optionale dritte Argument ist der Objektkontext (im Grunde genommen innerhalb der Schleife als 'this' bezeichnet).

Es gibt verschiedene Möglichkeiten, die forEach-Winkelschleife zu verwenden. Das einfachste und wahrscheinlich am häufigsten verwendete ist

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

Eine andere Möglichkeit, um Elemente von einem Array in ein anderes zu kopieren, 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.forEachFunktion im Gegensatz zu der eingebauten forSchleife mit Vanillegeschmack .

Vorteile

  • Einfache Lesbarkeit
  • Einfache Beschreibbarkeit
  • Wenn verfügbar, angular.forEachwird die ES5 forEach-Schleife verwendet. Jetzt werde ich im Abschnitt Nachteile zur Effizienz kommen, da die forEach-Schleifen viel langsamer sind als die for-Schleifen. Ich erwähne dies als Profi, weil es schön ist, konsistent und standardisiert zu sein.

Betrachten Sie die folgenden 2 verschachtelten Schleifen, die genau dasselbe tun. Angenommen, wir haben zwei Arrays von Objekten und jedes Objekt enthält ein Array von Ergebnissen, von denen jedes eine Value-Eigenschaft hat, die eine Zeichenfolge ist (oder was auch immer). Nehmen wir an, wir müssen jedes der Ergebnisse durchlaufen und wenn sie gleich sind, führen Sie 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 for Loops mit dem zweiten Ansatz geschrieben und es war sehr schwer zu lesen und zu schreiben.

Nachteile

  • Effizienz. angular.forEachund die Eingeborenen forEachsind beide so viel langsamer als die normale forSchleife ... ungefähr 90% langsamer . Bei großen Datenmengen sollten Sie sich am besten an die native Datenmenge haltenfor Schleife.
  • Keine Unterbrechung, Fortsetzung oder Rückgabe der Unterstützung. continuewird tatsächlich durch " Unfall " unterstützt, um fortzufahren, indem angular.forEachSie einfach eine return;Anweisung in die Funktion einfügen, angular.forEach(array, function(item) { if (someConditionIsTrue) return; });die dazu führt, dass die Funktion für diese Iteration fortgesetzt wird. Dies liegt auch an der Tatsache, dass der Native forEachweder break unterstützt noch fortfährt.

Ich bin mir sicher, dass es noch verschiedene andere Vor- und Nachteile gibt, und Sie können gerne alle hinzufügen, die Sie für richtig halten. Ich bin der Meinung, dass Sie, wenn Sie Effizienz benötigen, nur die native forSchleife für Ihre Schleifenanforderungen verwenden müssen. Aber wenn Ihre Datensätze kleiner sind und eine gewisse Effizienz in Ordnung ist, um im Austausch für Lesbarkeit und Schreibbarkeit aufzugeben, dann werfen Sie auf jeden Fall einen angular.forEachin diesen bösen Jungen.


34

Wenn es Ihnen nichts ausmacht, das Array zu leeren:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

xenthält den letzten Wert von yund wird aus dem Array entfernt. Sie können auch verwenden shift(), um das erste Element zu geben und zu entfernen y.


4
Es funktioniert nicht, wenn Sie zufällig ein spärliches Array wie haben [1, 2, undefined, 3].
M. Grzywaczewski

2
... oder in der Tat irgendetwas Falsey: [1, 2, 0, 3]oder[true, true, false, true]
joeytwiddle

31

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

2
Der Iterator führt dabei eine unnötige Längenberechnung durch. Im Idealfall sollte die Listenlänge nur einmal berechnet werden.
MIdhun Krishna

2
@MIdhunKrishna Ich habe meine Antwort und die jsFiddle aktualisiert, aber sei dir bewusst, dass es nicht so einfach ist, wie du denkst. Überprüfen Sie diese Frage
nmoliveira

2
Die vollständige und richtige Implementierung finden Sie hier: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
marciowb

29

Wahrscheinlich ist die for(i = 0; i < array.length; i++)Schleife nicht die beste Wahl. Warum? Wenn Sie dies haben:

var array = new Array();
array[1] = "Hello";
array[7] = "World";
array[11] = "!";

Die Methode ruft von array[0]bis auf array[2]. Erstens werden zuerst Variablen referenziert, die Sie nicht einmal haben, zweitens würden Sie die Variablen nicht im Array haben, und drittens wird der Code dadurch mutiger. Schau her, es ist was ich benutze:

for(var i in array){
    var el = array[i];
    //If you want 'i' to be INT just put parseInt(i)
    //Do something with el
}

Und wenn Sie möchten, dass es eine Funktion ist, können Sie dies tun:

function foreach(array, call){
    for(var i in array){
        call(array[i]);
    }
}

Wenn Sie brechen wollen, etwas mehr Logik:

function foreach(array, call){
    for(var i in array){
        if(call(array[i]) == false){
            break;
        }
    }
}

Beispiel:

foreach(array, function(el){
    if(el != "!"){
        console.log(el);
    } else {
        console.log(el+"!!");
    }
});

Es gibt zurück:

//Hello
//World
//!!!

29

Es gibt drei Implementierungen foreachin jQuery wie folgt.

var a = [3,2];

$(a).each(function(){console.log(this.valueOf())}); //Method 1
$.each(a, function(){console.log(this.valueOf())}); //Method 2
$.each($(a), function(){console.log(this.valueOf())}); //Method 3

2
Das Konsolenprotokoll ist nur für die Demo gedacht. Das soll es zu einem vollständigen Beispiel machen.
Rajesh Paul

29

Ab ECMAScript 6:

list = [0, 1, 2, 3]
for (let obj of list) {
    console.log(obj)
}

Wobei ofdie damit verbundenen Kuriositäten vermieden werden inund es wie die forSchleife einer anderen Sprache funktioniert und letbindeti innerhalb der Schleife im Gegensatz zu innerhalb der Funktion.

Die geschweiften Klammern ( {}) können weggelassen werden, wenn nur ein Befehl vorhanden ist (z. B. im obigen Beispiel).


28

Eine einfache Lösung wäre jetzt die Verwendung der Bibliothek underscore.js . Es bietet viele nützliche Tools, z. B. eachund delegiert den Job automatisch an den Native, forEachfalls verfügbar.

Ein CodePen-Beispiel für die Funktionsweise ist:

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

Siehe auch


23

for eachIn nativem JavaScript gibt es keine Schleife . Sie können entweder Bibliotheken verwenden, um diese Funktionalität zu erhalten (ich empfehle Underscore.js ), oder eine einfache forIn-Schleife verwenden.

for (var instance in objects) {
   ...
}

Beachten Sie jedoch, dass es Gründe geben kann, eine noch einfachere forSchleife zu verwenden (siehe Frage zum Stapelüberlauf Warum ist die Verwendung von „for… in“ mit Array-Iteration eine so schlechte Idee? )

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

22

Dies ist ein Iterator für eine nicht spärliche Liste, bei der der Index bei 0 beginnt. Dies ist das typische Szenario beim Umgang mit document.getElementsByTagName oder document.querySelectorAll.

function each( fn, data ) {

    if(typeof fn == 'string')
        eval('fn = function(data, i){' + fn + '}');

    for(var i=0, L=this.length; i < L; i++) 
        fn.call( this[i], data, i );   

    return this;
}

Array.prototype.each = each;  

Anwendungsbeispiele:

Beispiel 1

var arr = [];
[1, 2, 3].each( function(a){ a.push( this * this}, arr);
arr = [1, 4, 9]

Beispiel 2

each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');

Jedes p-Tag wird erhalten class="blue"

Beispiel 3

each.call(document.getElementsByTagName('p'), 
    "if( i % 2 == 0) this.className = data;",
    'red'
);

Jedes zweite p-Tag erhält class="red">

Beispiel 4

each.call(document.querySelectorAll('p.blue'), 
    function(newClass, i) {
        if( i < 20 )
            this.className = newClass;
    }, 'green'
);

Und schließlich werden die ersten 20 blauen p-Tags in grün geändert

Vorsicht bei der Verwendung von Zeichenfolgen als Funktion: Die Funktion wird außerhalb des Kontexts erstellt und sollte nur verwendet werden, wenn Sie sich des variablen Bereichs sicher sind. Andernfalls ist es besser, Funktionen zu übergeben, bei denen das Scoping intuitiver ist.


21

Es gibt einige Möglichkeiten , ein Array in JavaScript zu durchlaufen:

für - es ist das häufigste . Vollständiger Codeblock für die Schleife

var languages = ["Java", "JavaScript", "C#", "Python"];
var i, len, text;
for (i = 0, len = languages.length, text = ""; i < len; i++) {
    text += languages[i] + "<br>";
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

while - Schleife, während eine Bedingung durch ist. Es scheint die schnellste Schleife zu sein

var text = "";
var i = 0;
while (i < 10) {
    text +=  i + ") something<br>";
    i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

do / while - Durchläuft auch einen Codeblock, während die Bedingung erfüllt ist, und wird mindestens einmal ausgeführt

var text = ""
var i = 0;

do {
    text += i + ") something <br>";
    i++;
}
while (i < 10);

document.getElementById("example").innerHTML = text;
<p id="example"></p>

Funktionsschleifen - forEach, map, filter, auch reduce(sie Schleife durch die Funktion, aber sie verwendet werden , wenn Sie etwas mit Ihrem Array tun müssen, usw.

// For example, in this case we loop through the number and double them up using the map function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>

Weitere Informationen und Beispiele zur funktionalen Programmierung auf Arrays finden Sie im Blogbeitrag Funktionale Programmierung in JavaScript: Zuordnen, Filtern und Reduzieren .


Kleine Korrektur: forEachist keine "funktionale" Schleife, da sie keine neue Arrayzurückgibt (eigentlich gibt sie nichts zurück), sondern nur iteriert.
Nicholaswmin

19

ECMAScript 5 (die Version auf JavaScript) für die Arbeit mit Arrays:

forEach - Durchläuft jedes Element im Array und macht mit jedem Element alles, was Sie brauchen.

['C', 'D', 'E'].forEach(function(element, index) {
  console.log(element + " is #" + (index+1) + " in the musical scale");
});

// Output
// C is the #1 in musical scale
// D is the #2 in musical scale
// E is the #3 in musical scale

Falls Sie sich mehr für den Betrieb eines Arrays mit einer eingebauten Funktion interessieren.

map - Erstellt ein neues Array mit dem Ergebnis der Rückruffunktion. Diese Methode eignet sich gut, wenn Sie die Elemente Ihres Arrays formatieren müssen.

// Let's upper case the items in the array
['bob', 'joe', 'jen'].map(function(elem) {
  return elem.toUpperCase();
});

// Output: ['BOB', 'JOE', 'JEN']

reduzieren - Wie der Name schon sagt, wird das Array auf einen einzelnen Wert reduziert, indem die angegebene Funktion aufgerufen wird, die das aktuelle Element und das Ergebnis der vorherigen Ausführung übergibt.

[1,2,3,4].reduce(function(previous, current) {
  return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10

every - Gibt true oder false zurück, wenn alle Elemente im Array den Test in der Rückruffunktion bestehen.

// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];
ages.every(function(elem) {
  return elem >= 18;
});

// Output: false

filter - Sehr ähnlich zu allen, außer dass der Filter ein Array mit den Elementen zurückgibt, die für die angegebene Funktion true zurückgeben.

// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
  return (elem % 2 == 0)
});

// Output: [2,4,6]

16

Es gibt keine eingebaute Fähigkeit, einzubrechen forEach. Um die Ausführung zu unterbrechen, gehen Sie Array#somewie folgt vor:

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

Dies funktioniert, weil sometrue zurückgegeben wird, sobald einer der in Array-Reihenfolge ausgeführten Rückrufe true zurückgibt und die Ausführung des Restes kurzschließt. Ursprüngliche Antwort siehe Array-Prototyp für einige


13

Ich möchte dies auch als Komposition einer Rückwärtsschleife und als Antwort oben für jemanden hinzufügen, der diese Syntax ebenfalls möchte.

var foo = [object,object,object];
for (var i = foo.length, item; item = foo[--i];) {
    console.log(item);
}

Vorteile:

Der Vorteil dafür: Sie haben die Referenz bereits in der ersten, so dass sie später nicht mit einer anderen Zeile deklariert werden muss. Dies ist praktisch, wenn Sie das Objektarray durchlaufen.

Nachteile:

Dies wird immer dann unterbrochen, wenn die Referenz falsch ist - Falsey (undefiniert usw.). Es kann jedoch als Vorteil genutzt werden. Es würde jedoch das Lesen etwas erschweren. Und je nach Browser kann es "nicht" optimiert werden, um schneller als das Original zu arbeiten.


12

jQuery Weg mit $.map:

var data = [1, 2, 3, 4, 5, 6, 7];

var newData = $.map(data, function(element) {
    if (element % 2 == 0) {
        return element;
    }
});

// newData = [2, 4, 6];

1
Ich denke, die Ausgabe ist wahrscheinlicher [undefined, 2, undefined, 4, undefined, 6, undefined].

10

Verwenden von Schleifen mit ECMAScript 6- Destrukturierung und dem Spread-Operator

Die Destrukturierung und Verwendung des Spread-Operators hat sich für Neulinge in ECMAScript 6 als sehr gut lesbar / ästhetisch erwiesen, obwohl einige JavaScript-Veteranen dies möglicherweise als chaotisch betrachten. Junioren oder andere Leute könnten es nützlich finden.

In den folgenden Beispielen werden die for...ofAnweisung und die .forEachMethode verwendet.

Beispiele 6, 7 und 8 können mit beliebigen Funktionsschleifen verwendet werden , wie .map, .filter, .reduce, .sort, .every, .some. Weitere Informationen zu diesen Methoden finden Sie im Array-Objekt .

Beispiel 1: Normale for...ofSchleife - hier keine Tricks.

let arrSimple = ['a', 'b', 'c'];

for (let letter of arrSimple) {
  console.log(letter);
}

Beispiel 2: Wörter in Zeichen teilen

let arrFruits = ['apple', 'orange', 'banana'];

for (let [firstLetter, ...restOfTheWord] of arrFruits) {
  // Create a shallow copy using the spread operator
  let [lastLetter] = [...restOfTheWord].reverse();
  console.log(firstLetter, lastLetter, restOfTheWord);
}

Beispiel 3: Schleifen mit einem keyundvalue

// let arrSimple = ['a', 'b', 'c'];

// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`
// this example will use a multi-dimensional array of the following format type:
// `arrWithIndex: [number, string][]`

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Same thing can be achieved using `.map` method
// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);

// Same thing can be achieved using `Object.entries`
// NOTE: `Object.entries` method doesn't work on Internet Explorer  unless it's polyfilled
// let arrWithIndex = Object.entries(arrSimple);

for (let [key, value] of arrWithIndex) {
  console.log(key, value);
}

Beispiel 4: Inline-Objekteigenschaften abrufen

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];

for (let { name, age: aliasForAge } of arrWithObjects) {
  console.log(name, aliasForAge);
}

Beispiel 5: Holen Sie sich tiefe Objekteigenschaften von dem, was Sie brauchen

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
  console.log(name, firstItemFromTags, restOfTags);
}

Beispiel 6: Wird Beispiel 3 verwendet mit.forEach

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Not to be confused here, `forEachIndex` is the real index
// `mappedIndex` was created by "another user", so you can't really trust it

arrWithIndex.forEach(([mappedIndex, item], forEachIndex) => {
  console.log(forEachIndex, mappedIndex, item);
});

Beispiel 7: Wird Beispiel 4 verwendet mit.forEach

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];
// NOTE: Destructuring objects while using shorthand functions
// are required to be surrounded by parentheses
arrWithObjects.forEach( ({ name, age: aliasForAge }) => {
  console.log(name, aliasForAge)
});

Beispiel 8: Wird Beispiel 5 verwendet mit.forEach

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

arrWithObjectsWithArr.forEach(({
  name,
  tags: [firstItemFromTags, ...restOfTags]
}) => {
  console.log(name, firstItemFromTags, restOfTags);
});


7

Ein Weg, der Ihrer Idee am nächsten kommt, wäre die Verwendung Array.forEach()einer Schließfunktion, die für jedes Element des Arrays ausgeführt wird.

myArray.forEach(
  (item) => {
    // Do something
    console.log(item);
  }
);

Ein anderer praktikabler Weg wäre die Verwendung, Array.map()die auf die gleiche Weise funktioniert, aber auch alle Werte, die Sie zurückgeben, in einem neuen Array zurückgibt (im Wesentlichen jedes Element einem neuen zuzuordnen), wie folgt:

var myArray = [1, 2, 3];
myArray = myArray.map(
  (item) => {
    return item + 1;
  }
);

console.log(myArray); // [2, 3, 4]

1
Dies ist falsch, mapmutiert die Elemente des Arrays nicht, da ein neues Array zurückgegeben wird, wobei die Elemente dieses neuen Arrays das Ergebnis der Anwendung der Funktion auf die Elemente des alten Arrays sind.
Jesús Franco

Ich habe nie gesagt, dass kein neues Array zurückgegeben wird. Ich habe mich auf die von der Funktion vorgenommene Änderung bezogen. Aber hier werde ich es in der Antwort ändern.
Ante Jablan Adamović

wieder falsch, die Karte ändert oder mutiert nicht alle Elemente im ursprünglichen Array. Ich habe die Antwort vorgeschlagen und bearbeitet, wobei hervorgehoben wird, dass die Karte mit einer Kopie der ursprünglichen Elemente funktioniert , wobei das ursprüngliche Array überhaupt unberührt bleibt
Jesús Franco

7

Sie können forEach so anrufen:

forEachiteriert über das von Ihnen bereitgestellte Array und für jede Iteration, elementdie den Wert dieser Iteration enthält. Wenn Sie einen Index benötigen, können Sie den aktuellen Index erhalten, indem Sie den übergebeni als zweiten Parameter in der Rückruffunktion für forEach übergeben.

Foreach ist im Grunde eine Funktion hoher Ordnung, die eine andere Funktion als Parameter verwendet.

let theArray= [1,3,2];

theArray.forEach((element) => {
  // Use the element of the array
  console.log(element)
}

Ausgabe:

1
3
2

Sie können auch über ein Array wie folgt iterieren:

for (let i=0; i<theArray.length; i++) {
  console.log(i); // i will have the value of each index
}

6

Wenn Sie ein Array von Objekten mit der Pfeilfunktion durchlaufen möchten:

let arr = [{name:'john', age:50}, {name:'clark', age:19}, {name:'mohan', age:26}];

arr.forEach((person)=>{
  console.log('I am ' + person.name + ' and I am ' + person.age + ' old');
})


6

Die Lambda-Syntax funktioniert normalerweise nicht in Internet Explorer 10 oder niedriger.

Ich benutze normalerweise die

[].forEach.call(arrayName,function(value,index){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});

Wenn Sie ein jQuery- Fan sind und bereits eine jQuery-Datei ausgeführt wird, sollten Sie die Positionen der Index- und Wertparameter umkehren

$("#ul>li").each(function(**index, value**){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});

5

Wenn Sie ein massives Array haben, sollten Sie es verwenden iterators, um eine gewisse Effizienz zu erzielen. Iteratoren ist eine Eigenschaft bestimmter JavaScript Sammlungen (wie Map, Set, String, Array). Auch for..ofverwendet iteratorunter der Haube.

Iteratoren verbessern die Effizienz, indem Sie die Elemente in einer Liste einzeln als Stream verwenden können. Das Besondere an einem Iterator ist, wie er eine Sammlung durchläuft. Andere Schleifen müssen die gesamte Sammlung im Voraus laden, um sie zu durchlaufen, während ein Iterator nur die aktuelle Position in der Sammlung kennen muss.

Sie greifen auf das aktuelle Element zu, indem Sie die nextMethode des Iterators aufrufen . Die nächste Methode gibt valuedas aktuelle Element und a zurück, booleanum anzuzeigen, wann Sie das Ende der Sammlung erreicht haben. Das folgende Beispiel zeigt das Erstellen eines Iterators aus einem Array.

Verwandeln Sie Ihr reguläres Array mit der folgenden values()Methode in einen Iterator :

    const myArr = [2,3,4]

let it = myArr.values();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

Sie können Ihr reguläres Array auch folgendermaßen in einen Iterator umwandeln Symbol.iterator:

const myArr = [2,3,4]

let it = myArr[Symbol.iterator]();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

Sie können Ihren Stammkunden auch arrayin einen iteratorsolchen verwandeln :

let myArr = [8, 10, 12];

function makeIterator(array) {
    var nextIndex = 0;
    
    return {
       next: function() {
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    };
};

var it = makeIterator(myArr);

console.log(it.next().value);   // {value: 8, done: false}
console.log(it.next().value);   // {value: 10, done: false}
console.log(it.next().value);   // {value: 12, done: false}
console.log(it.next().value);   // {value: undefined, done: true}

HINWEIS :

  • Iteratoren sind von Natur aus erschöpfbar.
  • Objekte sind nicht iterablestandardmäßig. Verwenden Sie for..inin diesem Fall , weil anstelle von Werten , die sie mit den Tasten funktionieren.

Sie können mehr über lesen iteration protocol hier .


5

Wenn Sie verwenden möchten forEach(), sieht es so aus:

theArray.forEach ( element => {
    console.log(element);
});

Wenn Sie verwenden möchten for(), sieht es so aus:

for(let idx = 0; idx < theArray.length; idx++){
    let element = theArray[idx];
    console.log(element);
}

4

Gemäß der neuen aktualisierten Funktion ECMAScript 6 (ES6) und ECMAScript 2015 können Sie die folgenden Optionen mit Schleifen verwenden:

für Schleifen

for(var i = 0; i < 5; i++){
  console.log(i);
}

// Output: 0,1,2,3,4

für ... in Schleifen

let obj = {"a":1, "b":2}

for(let k in obj){
  console.log(k)
}

// Output: a,b

Array.forEach ()

let array = [1,2,3,4]

array.forEach((x) => {
  console.log(x);
})

// Output: 1,2,3,4

für ... von Schleifen

let array = [1,2,3,4]

for(let x of array){
  console.log(x);
}

// Output: 1,2,3,4

while-Schleifen

let x = 0

while(x < 5){
  console.log(x)
  x++
}

// Output: 1,2,3,4

tun ... while-Schleifen

let x = 0

do{
  console.log(x)
  x++
}while(x < 5)

// Output: 1,2,3,4

4

Performance

Heute (2019.12.18) Ich führe Test auf meinem macOS v10.13.6 (High Sierra), auf Chrome v 79.0, Safari v13.0.4 und Firefox v71.0 (64 bit) - Schlussfolgerungen über Optimierung (und Mikro-Optimierung der Normalerweise lohnt es sich nicht, es in den Code einzuführen, da der Nutzen gering ist, aber die Komplexität des Codes zunimmt.

  • Es sieht so aus, als ob das traditionelle for i( Aa ) eine gute Wahl ist, um schnellen Code in allen Browsern zu schreiben.

  • Die anderen Lösungen wie for-of( Ad ), alle in Gruppe C. ... sind normalerweise 2 bis 10 (und mehr) Mal langsamer als Aa , aber für kleine Arrays ist es in Ordnung, sie zu verwenden - um die Klarheit des Codes zu erhöhen.

  • Die in n( Ab, Bb, Be ) zwischengespeicherten Schleifen mit Array-Länge sind manchmal schneller, manchmal nicht. Wahrscheinlich erkennen Compiler diese Situation automatisch und führen das Caching ein. Die Geschwindigkeitsunterschiede zwischen der zwischengespeicherten und der nicht zwischengespeicherten Version ( Aa, Ba, Bd ) betragen etwa ~ 1%. Es sieht also so aus, als wäre einführen neine Mikrooptimierung .

  • Die i--wie Lösungen , wo die Schleife beginnt mit dem letzten Array - Elemente ( Ac, Bc ) sind in der Regel ca. 30% langsamer als Vorwärts-Lösungen - wahrscheinlich der Grund dafür ist die Art und Weise der CPU - Speicher - Cache Arbeits - Vorwärts-Speicher Lesen ist optimal für die CPU - Caching). Es wird empfohlen, solche Lösungen NICHT zu verwenden.

Einzelheiten

In Tests berechnen wir die Summe der Array-Elemente. Ich führe einen Test für kleine Arrays (10 Elemente) und große Arrays (1M Elemente) durch und teile sie in drei Gruppen ein:

  • A - forTests
  • B - whileTests
  • C - andere / alternative Methoden

Browserübergreifende Ergebnisse

Ergebnisse für alle getesteten Browser

Geben Sie hier die Bildbeschreibung einBrowser **

Array mit 10 Elementen

Ergebnisse für Chrome. Sie können den Test auf Ihrem Rechner ausführen hier .

Geben Sie hier die Bildbeschreibung ein

Array mit 1.000.000 Elementen

Ergebnisse für Chrome. Sie können den Test auf Ihrem Rechner ausführen hier

Geben Sie hier die Bildbeschreibung ein


4

Zusammenfassung:

Wenn wir über ein Array iterieren, möchten wir häufig eines der folgenden Ziele erreichen:

  1. Wir möchten das Array durchlaufen und ein neues Array erstellen:

    Array.prototype.map

  2. Wir möchten das Array durchlaufen und kein neues Array erstellen:

    Array.prototype.forEach

    for..of Schleife

In JavaScript gibt es viele Möglichkeiten, diese beiden Ziele zu erreichen. Einige sind jedoch bequemer als andere. Im Folgenden finden Sie einige häufig verwendete Methoden (die bequemste IMO), um die Array-Iteration in JavaScript durchzuführen.

Neues Array erstellen: Map

map()ist eine Funktion, mit Array.prototypeder jedes Element eines Arrays transformiert und dann ein neues Array zurückgegeben werden kann. map()Nimmt als Argument eine Rückruffunktion und funktioniert folgendermaßen:

let arr = [1, 2, 3, 4, 5];

let newArr = arr.map((element, index, array) => {
  return element * 2;
})

console.log(arr);
console.log(newArr);

Der Rückruf, den wir map()als Argument übergeben haben, wird für jedes Element ausgeführt. Dann wird ein Array zurückgegeben, das dieselbe Länge wie das ursprüngliche Array hat. In diesem neuen Array wird das Element durch die Rückruffunktion transformiert, die als Argument an übergeben wirdmap() .

Der deutliche Unterschied zwischen mapeinem anderen Schleifenmechanismus wie forEachund einer for..ofSchleife besteht darin, dass mapein neues Array zurückgegeben wird und das alte Array intakt bleibt (es sei denn, Sie manipulieren es explizit mit "think like" splice).

Beachten Sie außerdem, dass der mapRückruf der Funktion die Indexnummer der aktuellen Iteration als zweites Argument bereitstellt. Gibt das dritte Argument außerdem das Array an, auf dem mapaufgerufen wurde? Manchmal können diese Eigenschaften sehr nützlich sein.

Schleife mit forEach

forEachist eine Funktion, die sich befindet und Array.prototypeeine Rückruffunktion als Argument verwendet. Diese Rückruffunktion wird dann für jedes Element im Array ausgeführt. Im Gegensatz zur map()Funktion gibt die Funktion forEach nichts zurück ( undefined). Zum Beispiel:

let arr = [1, 2, 3, 4, 5];

arr.forEach((element, index, array) => {

  console.log(element * 2);

  if (index === 4) {
    console.log(array)
  }
  // index, and oldArray are provided as 2nd and 3th argument by the callback

})

console.log(arr);

Genau wie die mapFunktion forEachliefert der Rückruf die Indexnummer der aktuellen Iteration als zweites Argument. Gibt das dritte Argument auch das Array an, für das forEachaufgerufen wurde?

Durchlaufen Sie Elemente mit for..of

Die for..ofSchleife durchläuft jedes Element eines Arrays (oder eines anderen iterierbaren Objekts). Es funktioniert folgendermaßen:

let arr = [1, 2, 3, 4, 5];

for(let element of arr) {
  console.log(element * 2);
}

Im obigen Beispiel elementsteht für ein Array-Element und arrist das Array, das wir schleifen möchten. Beachten Sie, dass der Nameelement willkürlich ist und wir einen anderen Namen wie 'el' oder etwas aussagekräftigeres wählen könnten, wenn dies zutreffend ist.

Verwechseln Sie die for..inSchleife nicht mit der for..ofSchleife. for..inDurchläuft alle aufzählbaren Eigenschaften des Arrays, während die for..ofSchleife nur die Array-Elemente durchläuft. Zum Beispiel:

let arr = [1, 2, 3, 4, 5];

arr.foo = 'foo';

for(let element of arr) {
  console.log(element);
}

for(let element in arr) {
  console.log(element);
}

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.