Für jedes Array in Javascript?

Wie kann ich alle Einträge in einem Array mit Javascript anzeigen?

Ich dachte, es wäre so etwas:

 forEach(instance in theArray) 

Wo theArray ist mein Array, aber es scheint falsch zu sein.

4041
17 февр. Dante1986 am 17. Februar eingestellt 2012-02-17 16:51 '12 um 16:51 Uhr 2012-02-17 16:51
@ 32 Antworten
  • 1
  • 2

Tl; DR

  • Verwenden Sie kein for-in wenn Sie es nicht mit Schutz verwenden oder zumindest nicht wissen, warum es Sie beißen kann.
  • Ihre besten Einsätze sind normalerweise

    • for-of Schleife (nur für ES2015 +),
    • Array#forEach ( spec | MDN ) (oder dessen Verwandten und so) (nur ES5 +)
    • einfach altmodisch for Schleifen,
    • oder for-in Eingabe mit Schutz.

Aber es gibt noch viel zu entdecken, lesen Sie weiter ...


JavaScript verfügt über eine leistungsstarke Semantik für die zyklische Transformation von Arrays und Objekten des Array-Typs. Ich habe die Antwort in zwei Teile geteilt: Optionen für authentische Arrays und Optionen für Dinge, die nur Arrays ähneln, wie das arguments , andere iterierbare Objekte (ES2015 +), DOM-Sammlungen usw.

Ich stelle schnell fest, dass Sie die ES2015-Optionen jetzt auch auf ES5-Engines verwenden können, indem Sie ES2015 an ES5 senden. Finden Sie "ES2015 transpiling" / "ES6 transpiling" für mehr ...

Schauen Sie sich unsere Optionen an:

Für echte Arrays

Sie haben drei Optionen in ECMAScript 5 ("ES5"), die derzeit am meisten unterstützte Version, und zwei weitere in ECMAScript 2015 ("ES2015", "ES6"):

  1. Verwenden Sie forEach und verwandte (ES5 +)
  2. Verwenden Sie eine einfache for Schleife
  3. Richtig for-in
  4. for-of (impliziter Iterator verwenden) (ES2015 +)
  5. Iterator explizit verwenden (ES2015 +)

Details:

1. Verwenden Sie forEach und verwandte

In einer unendlich modernen Umgebung (naja, nicht in IE8), in der Sie Zugriff auf die von ES5 hinzugefügten Array Funktionen haben (direkt oder unter Verwendung von Polyple-Füllungen), können Sie forEach ( spec | MDN ) verwenden:

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

forEach akzeptiert eine Callback-Funktion und optional einen Wert, der beim Aufruf dieses Callbacks (wie oben nicht verwendet) verwendet wird. 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 nur ein Argument oben verwendet habe, wird der Rückruf mit drei aufgerufen: der Wert jedes Datensatzes, der Index dieses Datensatzes und der Link zu dem Array, das Sie wiederholen (falls Ihre Funktion es noch nicht hat).

Wenn Sie keine älteren Browser wie IE8 unterstützen (wie NetApps zum Zeitpunkt der Veröffentlichung dieses Dokuments im September 2016 mehr als 4% des Marktes ausmachte), können Sie forEach problemlos auf einer universellen Webseite ohne Seitenlayout verwenden. Wenn Sie veraltete Browser unterstützen müssen, ist es einfach, den Vorgang "Shimming / Polyfilling forJach" auszuführen ("es5 shim" für mehrere Optionen).

forEach hat den Vorteil, dass Sie keine Indizierungs- und Variablenwerte im Inhaltsbereich deklarieren müssen, da sie als Argumente für die Iterationsfunktion angegeben werden und so gut auf diese Iteration ausgerichtet sind.

Wenn Sie sich Sorgen machen, wie >Details

Darüber hinaus ist forEach eine "Schleife durch sie alle" -Funktion, aber ES5 hat einige andere nützliche "Ausarbeitungen durch Array-Funktionen und -Dinge" definiert, darunter:

  • every (stoppt die Schleife, wenn der Callback das erste Mal false oder etwas Falsches zurückgibt)
  • some (stoppt die Schleife, wenn der Callback das erste Mal true oder etwas Plausibles zurückgibt)
  • filter (erstellt ein neues Array, das Elemente enthält, in denen die Filterfunktion " true zurückgibt und die Elemente weglässt, in denen " false )
  • map (erstellt ein neues Array von Rückrufwerten)
  • reduce (Inkrementieren eines Wertes, erneutes Aufrufen eines Rückrufs, Übergeben vorheriger Werte, Details finden Sie in der Spezifikation, nützlich zum Summieren des Inhalts eines Arrays und viele andere Dinge)
  • reduceRight (z. B. reduce , funktioniert jedoch in absteigender Reihenfolge, nicht in aufsteigender Reihenfolge)

2. Verwenden Sie eine einfache for Schleife

Manchmal sind die alten Wege am besten:

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

Wenn sich die Arraylänge während des Zyklus nicht ändert und die Leistung empfindlicher Code ist (unwahrscheinlich), kann eine etwas kompliziertere Version des Captures mit der vorderen Länge etwas schneller sein:

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

Und / oder zurückzählen:

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

Aber mit modernen JavaScript-Mechanismen müssen Sie diesen letzten Saft selten ausgraben.

In ES2015 und höher können Sie Ihre Index- und Wertvariablen for for Schleifen lokalisieren:

 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" 

Wenn Sie dies tun, wird nicht nur der value sondern auch der index für jede Iteration der Schleife neu erstellt. Das heißt, die im Loop-Tag erstellten Schließungen enthalten eine Referenz auf den index (und den value ), die für diese bestimmte Iteration erstellt wurden:

 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 is: 0" erhalten, wenn Sie auf das erste und "Index ist: 4" geklickt haben, wenn Sie auf das letzte geklickt haben. Dies funktioniert nicht , wenn Sie var anstelle von let .

3. for-in richtig verwenden.

Sie erhalten Leute, die Ihnen sagen, dass Sie for-in , aber dafür ist for-in nicht gedacht . for-in durch die aufgezählten Eigenschaften des Objekts und nicht durch die Arrayindizes geschrieben. Bestellung nicht garantiert , auch in ES2015 (ES6). ES2015 bestimmt die Reihenfolge der Eigenschaften eines Objekts (unter Verwendung von [[OwnPropertyKeys]] , [[Enumerate]] und von Dingen, die sie als Object.getOwnPropertyKeys ), legt jedoch nicht fest , dass das for-in dieser Reihenfolge folgt. (Details in dieser anderen Antwort .)

Dies kann jedoch insbesondere für spärliche Arrays nützlich sein, wenn Sie die entsprechenden Vorsichtsmaßnahmen 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 unter diesem Namen eine eigene Eigenschaft hat (und nicht diejenige, die es von seinem Prototyp erbt) und

  2. Der Schlüssel ist eine numerische Basis-10-Zeichenfolge in der üblichen Zeichenfolgenform und der Wert ist <= 2 ^ 32 - 2 (dh 4.294.967.294). Woher kommt diese Nummer? Dies ist Teil der Array-Indexdefinition in der Spezifikation . Andere Zahlen (nicht ganzzahlige Zahlen, negative Zahlen, Zahlen größer als 2 ^ 32 - 2) sind keine Arrayindizes. Die Ursache von 2 ^ 32 - 2 ist der, der den höchsten Indexwert unter 2 ^ 32 - 1 , den maximalen Wert der length Arrays, verringert. (Die Array-Länge entspricht beispielsweise einer vorzeichenlosen 32-Bit-Ganzzahl.) (Eine Bestätigung von RobG, die in einem Kommentar zu meinem Blogbeitrag darauf hinweist, dass mein vorheriger Test nicht ganz richtig war).

Dies ist ein kleines bisschen zusätzlicher Aufwand für jede Wiederholung von Schleifen in den meisten Arrays. Wenn Sie jedoch ein spärliches Array haben, ist dies möglicherweise eine effizientere Methode zum Schleifen, da dies nur Schleifen für tatsächlich vorhandene Datensätze sind. Für das obige Array wird beispielsweise drei Mal eine Schleife durchlaufen (für die Tasten "0" , "10" und "10000" - denken Sie daran, dies sind Zeilen), und nicht 10.001-mal.

Jetzt möchten Sie es nicht jedes Mal schreiben, also können Sie es in Ihr Toolkit aufnehmen:

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

Und dann benutzen wir es so:

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

Wenn Sie nur an dem Test interessiert sind, der für die meisten Fälle gut genug ist, können Sie ihn verwenden, aber so>

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

4. for-of (impliziter Iterator verwenden) (ES2015 +)

ES2015 fügt JavaScript Iteratoren hinzu. Der einfachste Weg, Iteratoren zu verwenden, ist der neue for-of Operator. Es sieht so aus:

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

Fazit:

 a b c

Unter den Covers, die einen Iterator aus dem Array abrufen und durchlaufen, erhalten sie Werte. Es gibt kein Problem mit der Verwendung von for-in , da ein von einem Objekt (Array) definierter Iterator verwendet wird und Arrays bestimmen, dass ihre Iteratoren ihre Datensätze (und nicht ihre Eigenschaften) wiederholen. Im Gegensatz zu for-in in ES5 ist die Reihenfolge, in der Datensätze angezeigt werden, die numerische Reihenfolge ihrer Indizes.

5. Verwenden Sie den Iterator explizit (ES2015 +).

Manchmal können Sie explizit einen Iterator verwenden. Sie können dies auch tun, obwohl es viel klobiger als for-of . Es sieht so aus:

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

Ein Iterator ist ein Objekt, das der Iterator-Definition in der Spezifikation entspricht. Seine next Methode gibt bei jedem Aufruf ein neues Ergebnisobjekt zurück. Das Ergebnisobjekt verfügt über eine Eigenschaft done , die uns sagt, ob es gemacht wurde, und den value Eigenschaft mit dem Wert für diese Iteration. ( done optional, wenn es false , value ist optional, wenn es nicht undefined ).

Der value variiert je nach Iterator. Arrays unterstützen (mindestens) drei Funktionen, die Iteratoren zurückgeben:

  • values() : Dies ist das, das ich oben verwendet habe. Es gibt einen Iterator zurück, wobei jeder value ein Array-Datensatz für diese Iteration ist ( "a" , "b" und "c" im obigen Beispiel).
  • keys() : Gibt einen Iterator zurück, wobei jeder value der Schlüssel für diese Iteration ist (bei uns oben wird es also a "0" und dann "1" und dann "2" ).
  • entries() : Gibt einen Iterator zurück, wobei jeder value ein Array in Form von [key, value] für diese Iteration ist.

Für Objekte wie ein Array

Neben echten Arrays gibt es auch NodeList Objekte mit der length Eigenschaft und Eigenschaften mit numerischen Namen: NodeList Instanzen, ein arguments usw. Wie NodeList wir deren Inhalte?

Verwenden Sie einen der obigen Parameter für Arrays.

Zumindest einige und möglicherweise die meisten oder sogar alle der oben genannten Arrays werden für Objekte des Array-Typs häufig gleich gut verwendet:

  1. Verwenden Sie forEach und verwandte (ES5 +)

    Die verschiedenen Funktionen in Array.prototype sind "absichtlich generisch" und können normalerweise für Objekte wie ein Array verwendet werden, indem Function#call Function#apply oder Function#apply angewendet wird. (Informationen zu vom Host bereitgestellten Objekten finden Sie am Ende dieser Antwort unter Disclaimer. Dies ist jedoch ein seltenes Problem.)

    Angenommen, Sie wollten forEach in childNodes Node childNodes . Sie würden 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 in einer Variablen erhalten, die wiederverwendet werden soll. Beispiel:

     // (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 for Schleife

    Offensichtlich wird eine einfache for Schleife auf Objekte wie ein Array angewendet.

  3. Richtig for-in

    for-in mit den gleichen Garantien wie bei einem Array, sollte mit Objekten arbeiten, die einem Array ähneln; Für vom Gastgeber zur Nummer 1 bereitgestellte Gegenstände können Reservierungen erforderlich sein.

  4. for-of (impliziter Iterator verwenden) (ES2015 +)

    for-of wird den vom Objekt bereitgestellten Iterator verwenden (falls vorhanden); Wir müssen sehen, wie dies bei verschiedenen Array-artigen Objekten geschieht, insbesondere bei Host-Dateien. Beispielsweise wurde die Spezifikation für die NodeList von querySelectorAll zur Unterstützung der Iteration aktualisiert. Die Spezifikation für die HTMLCollection von getElementsByTagName nicht.

  5. Iterator explizit verwenden (ES2015 +)

    Siehe Nummer 4, wir müssen sehen, wie sich Iteratoren entfalten.

Erstellen Sie ein echtes Array

In anderen Fällen können Sie ein Objekt wie ein Array in ein echtes Array konvertieren. Das ist überraschend einfach:

  1. Verwenden Sie die slice Array-Methode

    Wir können die slice Array-Methode verwenden, die wie die anderen oben genannten Methoden "absichtlich generisch" ist und daher mit arrayähnlichen Objekten verwendet werden kann, zum Beispiel:

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

    Wenn Sie beispielsweise eine NodeList in ein reales Array konvertieren möchten, können Sie NodeList tun:

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

    Siehe "Vorsicht für vom Host bereitgestellte Objekte" weiter unten. Beachten Sie insbesondere, dass dies in IE8 und früheren Versionen nicht funktioniert, was die Verwendung von Objekten, die vom Host bereitgestellt werden, nicht zulässt.

  2. Verteilungssyntax verwenden ( ... )

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

     var trueArray = [...iterableObject]; 

    Wenn wir beispielsweise eine NodeList mit der Ausbreitungssyntax in ein echtes Array konvertieren NodeList , wird es recht kurz:

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

    Array.from (ES2015 +, aber leicht mit Poly gefüllt) erstellt ein Array aus einem Objekt wie einem Array, falls erforderlich, wobei zuerst Datensätze durch die entsprechende Funktion geleitet werden. Also:

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

    Wenn Sie ein Array von Tag-Namen für Elemente einer bestimmten Klasse abrufen möchten, müssen Sie die Mapping-Funktion verwenden:

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

Vorsicht bei Einrichtungen, die vom Gastgeber bereitgestellt werden

Wenn Sie Array.prototype Funktionen mit Objekten wie Hosts verwenden (DOM-Listen und andere vom Browser bereitgestellte Dinge anstelle der JavaScript-Engine), müssen Sie unbedingt in Ihren Zielumgebungen testen, um sicherzustellen, dass sich das bereitgestellte Hostobjekt verhält ist richtig. Die meisten von ihnen verhalten sich jetzt korrekt , aber es ist wichtig zu überprüfen. Der Grund ist, dass die meisten Array.prototype Methoden, die Sie wahrscheinlich verwenden möchten, auf das vom Host bereitgestellte Objekt angewiesen sind und eine ehrliche Antwort auf die Zusammenfassung [[HasProperty]] . Zum Zeitpunkt der Erstellung dieses Dokuments haben Browser dies sehr gut gemacht, aber die 5.1-Spezifikation legt nahe, dass das vom Host bereitgestellte Objekt möglicherweise nicht fair ist. Dies ist in §8.6.2 ein paar Absätze unterhalb der großen Tabelle am Anfang dieses Abschnitts, wo es heißt:

Host-Objekte können diese internen Methoden auf beliebige Weise implementieren, sofern nicht anders angegeben. Eine Möglichkeit ist beispielsweise, dass [[Get]] und [[Put]] für ein bestimmtes Host-Objekt zwar Eigenschaftswerte abrufen und speichern, [[HasProperty]] immer false generiert.

(Ich konnte in der ES2015-Spezifikation keinen entsprechenden Wortlaut finden, muss es aber immer noch sein.) Auch beim Schreiben eines allgemeinen Hosts des bereitgestellten Arrays von Objekttypen in modernen Browsern [zum Beispiel bei NodeList Instanzen] wird die [[HasProperty]] korrekt, aber wichtig behandelt überprüfen.)

6292
17 февр. Die Antwort wird von TJ Crowder 17 Feb. gegeben. 2012-02-17 16:53 '12 um 16:53 Uhr 2012-02-17 16:53

Edit : Diese Antwort ist hoffnungslos veraltet. Für einen moderneren Ansatz schauen Sie sich die verfügbaren Methoden im Array an . Methoden von Interesse können sein:

  • für jeden
  • Karte
  • der filter
  • Reißverschluss
  • reduzieren
  • jeder
  • ein bisschen

Die Standardmethode zum Durchlaufen eines Arrays in JavaScript ist for -loop vanilla:

border=0
 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 sinnvoll ist, wenn Sie ein dichtes Array haben und jeder Index von einem Element belegt wird. Wenn das Array spärlich ist, kann es bei diesem Ansatz zu Leistungsproblemen kommen, da Sie viele Indizes durchlaufen, die im Array nicht vorhanden sind. In diesem Fall ist es besser for.. in -loop zu verwenden. Sie müssen jedoch geeignete Vorkehrungen treffen, um sicherzustellen, dass nur die erforderlichen Eigenschaften des Arrays (d. for..in Arrayelemente) for..in , da for..in -loop auch in älteren Browsern aufgeführt wird oder wenn die zusätzlichen Eigenschaften als auflistbar definiert sind.

In ECMAScript 5 wird die forEach-Methode für den Array-Prototyp verwendet, in älteren Browsern jedoch nicht unterstützt. Um es einheitlich 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 "Polyfill" verwenden. Die Polyfill für diese Funktionalität ist jedoch trivial, und da der Code leichter lesbar ist, sollte er in die Polyfill aufgenommen werden.

470
17 февр. Antwort von PatrikAkerstrand am 17. Februar 2012-02-17 16:55 '12 um 16:55 Uhr 2012-02-17 16:55

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

 var length = yourArray.length; for (var i = 0; i < length; i++) { // Do something with yourArray[i]. } 
214
17 февр. Die Antwort ist Poonam 17. Februar gegeben. 2012-02-17 17:01 '12 am 17:01 2012-02-17 17:01

Schleife zurück

Ich denke, das Gegenteil für den Zyklus verdient hier eine Erwähnung:

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

Vorteile:

  • Sie müssen keine temporäre Variable len deklarieren oder sie bei jeder Iteration mit array.length vergleichen. array.length kann eine array.length sein.
  • Das Entfernen von Geschwistern aus dem DOM in umgekehrter Reihenfolge ist normalerweise effizienter . (Der Browser muss weniger Elemente in den internen Arrays verschieben.)
  • Wenn Sie während einer Schleife ein Array an oder nach einem Index I ändern (beispielsweise ein Element in array[i] löschen oder einfügen), überspringt eine direkte Schleife ein nach links verschobenes Element an Position i oder überprüft das verschobene i-te Element nach rechts In der traditionellen Schleife können Sie i aktualisieren, um auf das nächste Element zu verweisen, das verarbeitet werden muss - 1, aber das einfache Ändern der Iterationsrichtung ist oft eine einfachere und elegantere Lösung .
  • Wenn Sie verschachtelte DOM-Elemente ändern oder löschen, kann die umgekehrte Verarbeitung ebenfalls Fehler umgehen . Sie können beispielsweise vor dem Verarbeiten der untergeordneten Knoten die innerHTML des übergeordneten Knotens ändern. Wenn der untergeordnete Knoten erreicht ist, wird er vom DOM getrennt und durch einen neuen Nachkommen ersetzt, wenn das übergeordnete innerHTML geschrieben wurde.
  • kürzer und lesbarer als andere verfügbare Optionen. Obwohl es an forEach() und an ES6 for ... of verliert.

Nachteile:

  • Es verarbeitet die Artikel in umgekehrter Reihenfolge. Wenn Sie aus den Ergebnissen ein neues Array erstellt oder auf dem Bildschirm gedruckt haben, wird die Ausgabe natürlich relativ zur ursprünglichen Reihenfolge abgebrochen .
  • Неоднократно вставляя братьев и сестер в DOM в качестве первого ребенка, чтобы сохранить их порядок, менее эффективен . (В браузере все равно придется перекладывать вещи.) Чтобы создавать узлы DOM эффективно и упорядоченно, просто переходите вперед и добавьте как обычно (а также используйте "фрагмент документа" ).
  • Обратный цикл запутывает для младших разработчиков. (Вы можете считать это преимущество, в зависимости от вашего прогноза.)

Должен ли я всегда использовать его?

Некоторые разработчики используют обратный цикл для по умолчанию, если нет веской причины для перехода вперед.

Хотя прирост производительности обычно незначителен, это крики:

"Просто сделайте это для каждого элемента в списке, я не забочусь о заказе!"

Однако на практике это не на самом деле надежное указание на намерение, поскольку оно неотличимо от тех случаев, когда вы делаем заботиться о заказе и действительно выполняете нужна для обратной петли. Таким образом, на самом деле потребуется еще одна конструкция, чтобы точно выразить намерение "не заботиться", что в настоящее время недоступно на большинстве языков, включая ECMAScript, но которое можно назвать, например, forEachUnordered() .

Если порядок не имеет значения, а эффективность вызывает озабоченность (в самом внутреннем цикле движка игры или анимации), тогда может быть приемлемым использовать цикл обратного цикла, к рисунку. Просто помните, что просмотр обратного цикла в существующем коде не обязательно означает , что порядок не имеет значения!

Лучше использовать forEach()

В целом для кода более высокого уровня, где ясность и безопасность больше беспокоят, я бы рекомендовал использовать Array::forEach как ваш шаблон по умолчанию:

  • Ясно читать.
  • Это означает, что я не будет перемещаться внутри блока (что всегда является возможным сюрпризом, скрывающимся в длинных циклах for и while .)
  • Это дает вам свободу действий для закрытия.
  • Это уменьшает утечку локальных переменных и случайное столкновение с (и мутацией) внешних переменных.

Затем, когда вы видите обратное для цикла в своем коде, это намек на то, что он поменялся по уважительной причине (возможно, одна из причин, описанных выше). И, увидев традиционный цикл вперед, можно указать, что может произойти переключение.

(Если обсуждение намерения не имеет для вас никакого смысла, то вам и вашему коду может быть полезно посмотреть лекцию Крокфорда на Стиль программирования и ваш мозг .)


Wie funktioniert das?

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

Вы заметите, что i-- является средним предложением (где мы обычно видим сравнение), а последнее предложение пусто (где мы обычно видим i++ ). Это означает, что i-- также используется как условие продолжения. Реально, он выполняется и проверяется перед каждой итерацией.

  • Как он может начинаться с array.length без взрыва?

    Поскольку i-- запускается перед каждой итерацией, на первой итерации мы фактически получаем доступ к элементу в array.length - 1 , который избегает любых проблем с элементами Array-out-of-bounds undefined .

  • Почему он не останавливает итерацию перед индексом 0?

    Цикл прекратит итерацию, когда условие i-- оценивает значение false (когда оно дает 0).

    Фокус в том, что в отличие от --i , конечный оператор i-- уменьшает i , но дает значение до декремента. Ваша консоль может продемонстрировать это:

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

    [5, 5, 4]

    Итак, на последней итерации я ранее был 1 , а выражение i-- меняло его на 0 , но на самом деле дает 1 (правдиво), и поэтому условие проходит. На следующей итерации i-- меняет я на -1 , но дает 0 (falsey), заставляя выполнение немедленно выходить из нижней части цикла.

    В традиционном forwards for loop, i++ и ++i взаимозаменяемы (как указывает Дуглас Крокфорд). Однако в обратном для цикла, поскольку наш декремент также является выражением нашего условия, мы должны придерживаться i-- , если мы хотим обработать элемент в индексе 0.


Trivia

Некоторым людям нравится рисовать небольшую стрелку в обратном цикле for и заканчивать миганием:

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

Кредиты идут в WYL, чтобы показать мне преимущества и ужасы обратного цикла.

94
ответ дан joeytwiddle 02 мая '14 в 17:21 2014-05-02 17:21

Некоторые C -язычные языки используют foreach для циклического перебора. В JavaScript это делается с помощью структуры for..in :

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

Есть улов. for..in будет проходить через каждый из перечисляемых объектов и членов на его прототипе. Чтобы избежать считывания значений, которые наследуются через прототип объекта, просто проверьте, принадлежит ли свойство объекту:

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

Кроме того, ECMAScript 5 добавил foreach to Array.prototype , который может использоваться для перечисления по массиву с использованием calback (polyfill находится в документах, поэтому вы можете использовать его для более старых браузеров):

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

Важно отметить, что Array.prototype.forEach не прерывается, когда обратный вызов возвращает false . jQuery и Underscore.js предоставляют свои собственные варианты each , чтобы обеспечить петли, которые могут быть закорочены.

75
ответ дан zzzzBov 17 февр. '12 в 17:00 2012-02-17 17:00

Если вы хотите перебрать массив, используйте стандартный трехчастный цикл for .

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

Вы можете получить некоторую оптимизацию производительности путем кэширования myArray.length или повторения ее назад.

34
ответ дан Quentin 17 февр. '12 в 16:55 2012-02-17 16:55

Я знаю, что это старый пост, и есть много замечательных @. Для немного более полноты я решил, что я бы выбрал другой, используя AngularJS . Конечно, это применимо только в том случае, если вы используете Angular, очевидно, тем не менее, я все равно хочу его поместить.

angular.forEach принимает 2 аргумента и необязательный третий аргумент. Первый аргумент - это объект (массив) для итерации, второй аргумент - функция итератора, а необязательный третий аргумент - это контекст объекта (в основном называемый внутри цикла как 'this'.

Существуют разные способы использования цикла forEach для angular. Самый простой и, вероятно, наиболее используемый -

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

Другой способ, который полезен для копирования элементов из одного массива в другой, -

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

Хотя вам не обязательно это делать, вы можете просто сделать следующее и это эквивалентно предыдущему примеру:

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

Теперь есть плюсы и минусы использования функции angular.forEach , в отличие от встроенного в ванили ароматизированного цикла for .

Pros

  • Легкая читаемость
  • Легкая возможность записи
  • Если доступно, angular.forEach будет использовать цикл ES5 forEach. Теперь я получу эффективность в разделе cons, поскольку петли forEach намного медленнее, чем циклы for. Я упоминаю об этом как о профессионале, потому что приятно быть последовательным и стандартизованным.

Рассмотрим следующие два вложенных цикла, которые делают то же самое. Скажем, что у нас есть 2 массива объектов, и каждый объект содержит массив результатов, каждый из которых имеет свойство Value, которое содержит строку (или что-то еще). И пусть говорят, что нам нужно перебирать каждый из результатов, и если они равны, то выполните какое-то действие:

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

Конечно, это очень простой гипотетический пример, но я написал тройку, встроенную для циклов, используя второй подход, и было очень трудно читать и писать по этому поводу.

gegen

  • Эффективность. angular.forEach , и нативный forEach , если на то пошло, настолько медленнее, чем обычный цикл for .... о на 90% медленнее . Поэтому для больших наборов данных лучше всего придерживаться встроенного цикла for .
  • Нет поддержки перерыва, продолжения или возврата. continue на самом деле поддерживается авария ", чтобы продолжить в angular.forEach , вы просто положили оператор return; в функцию типа angular.forEach(array, function(item) { if (someConditionIsTrue) return; }); , который приведет к тому, что он продолжит работу для этой итерации. Это также связано с тем, что нативный forEach не поддерживает разрыв или продолжается либо.

Я уверен, что есть и другие плюсы и минусы, и, пожалуйста, не стесняйтесь добавлять все, что сочтете нужным. Я чувствую, что в нижней строке, если вам нужна эффективность, придерживайтесь только собственного цикла for для ваших нужд цикла. Но, если ваши наборы данных меньше, и некоторая эффективность в порядке, чтобы отказаться от обмена на удобочитаемость и возможность записи, то непременно бросьте angular.forEach на этого плохого мальчика.

27
ответ дан user2359695 21 июня '14 в 1:56 2014-06-21 01:56

A forEach ( см. в 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 } ); 
27
ответ дан nmoliveira 10 апр. '13 в 3:26 2013-04-10 03:26

Если вы не против опустошения массива:

 var x; while(x = y.pop()){ alert(x); //do something } 

x будет содержать последнее значение y , и оно будет удалено из массива. Вы также можете использовать shift() , который даст и удалит первый элемент из y .

27
ответ дан gaby de wilde 10 марта '13 в 5:37 2013-03-10 05:37

Легким решением теперь будет использование библиотеки underscore.js . Он предоставляет множество полезных инструментов, таких как each и автоматически делегирует задание на нативный forEach , если он доступен.

Пример CodePen о том, как он работает:

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

Siehe auch

25
ответ дан Micka 17 июля '13 в 12:07 2013-07-17 12:07

В jQuery существует три реализации foreach следующим образом.

 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 
23
ответ дан Rajesh Paul 25 дек. '13 в 19:14 2013-12-25 19:14

Вероятно, цикл for(i = 0; i < array.length; i++) не лучший выбор. Warum? Если у вас есть это:

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

Метод вызовет от array[0] до array[2] . Во-первых, это сначала будет ссылаться на переменные, которых у вас даже нет, во-вторых, у вас не будет переменных в массиве, а в-третьих, это сделает код более смелым. Послушайте, это то, что я использую:

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

И если вы хотите, чтобы это была функция, вы можете сделать это:

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

Если вы хотите сломать, немного логичнее:

 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+"!!"); } }); 

Он возвращает:

 //Hello //World //!!! 
22
ответ дан Federico Piragua 02 нояб. '13 в 5:23 2013-11-02 05:23

Как и ES6:

21
ответ дан Zaz 26 мая '16 в 19:14 2016-05-26 19:14

Для for each цикла в родном JavaScript нет ни одного. Вы можете использовать библиотеки, чтобы получить эту функцию (я рекомендую Underscore.js ), используйте простой for в цикле.

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

Тем не менее, обратите внимание, что могут быть причины, чтобы использовать еще проще for цикла (см переполнением стека вопрос Почему используется "для... в" с массивом итерационного такой плохой идеей? )

 var instance; for (var i=0; i < objects.length; i++) { var instance = objects[i]; ... } 
17
ответ дан joidegn 17 февр. '12 в 16:58 2012-02-17 16:58

Это итератор для нерезкого списка, где индекс начинается с 0, что является типичным сценарием при работе с document.getElementsByTagName или 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; 

Примеры использования:

Пример # 1

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

Пример # 2

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

Каждый тэг p получает class="blue"

Пример # 3

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

Каждый другой тег p получает class="red" >

Пример # 4

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

И, наконец, первые 20 синих p-тэгов меняются на зеленый

Предостережение при использовании функции string как функции: функция создается вне контекста и должна использоваться только там, где вы уверены в переменном охвате. В противном случае лучше передать функции, где область обзора более интуитивно понятна.

17
ответ дан Tim 30 янв. '14 в 18:25 2014-01-30 18:25

Существует несколько способов циклического преобразования массива в JavaScript, как показано ниже:

для - это самый распространенный. Полный блок кода для циклирования

 <p id="example"></p> 

while - loop, пока выполняется условие. Кажется, это самый быстрый цикл

 <p id="example"></p> 

do/while - также цикл через блок кода, пока условие истинно, будет выполняться как минимум один раз

 <p id="example"></p> 

Функциональные циклы - forEach , map , filter , также reduce (они прокручивают функцию, но используются, если вам нужно что-то делать с вашим массивом и т.д.

 <p id="example"></p> 

Для получения дополнительной информации и примеров о функциональном программировании на массивах, посмотрите на сообщение в блоге. Функциональное программирование в JavaScript: отображение, фильтрация и уменьшение .

16
ответ дан Alireza 10 мая '17 в 17:32 2017-05-10 17:32

ECMAScript5 (версия на Javascript) для работы с массивами.

forEach . Итерирует каждый элемент массива и делает все, что вам нужно, с каждым элементом.

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

В случае, более заинтересованный в работе над массивом с использованием некоторой встроенной функции.

map . Он создает новый массив с результатом функции обратного вызова. Этот метод хорош для использования, когда вам нужно отформатировать элементы вашего массива.

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

уменьшить . Как видно из названия, он уменьшает массив до одного значения, вызывая передачу данной функции в элементе currenct и результате предыдущего выполнения.

 [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 

каждый - возвращает true или false, если все элементы массива проходят тест в функции обратного вызова.

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

фильтр - очень похоже на каждый, кроме того, что фильтр возвращает массив с элементами, возвращающими true для данной функции.

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

Hoffe das ist hilfreich.

14
ответ дан Anil Kumar Arya 09 апр. '17 в 19:51 2017-04-09 19:51

Там нет встроенной способности взломать для forEach . Чтобы прервать выполнение, используйте Array#some как показано ниже:

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

Это работает, потому что some возвращают true, как только любой из обратных вызовов, выполненный в порядке массива, возвращает true, короткое замыкание выполнения остальных. Оригинальный ответ см. В прототипе Array для некоторых

14
ответ дан Priyanshu Chauhan 27 июля '15 в 10:07 2015-07-27 10:07

Я также хотел бы добавить это как состав обратной петли и ответ выше для тех, кто хотел бы также использовать этот синтаксис.

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

Pros:

Выгода для этого: у вас есть ссылка уже в первом, что не нужно будет объявлять позже с другой строкой. Это удобно при циклическом перемещении по массиву объектов.

Nachteile:

Это будет прерываться всякий раз, когда ссылка ложна - false (undefined и т.д.). Однако это можно использовать как преимущество. Однако, это сделало бы его немного труднее читать. А также в зависимости от браузера он может быть "не" оптимизирован для работы быстрее оригинального.

11
ответ дан Volkan Seçkin Akbayır 28 авг. '15 в 10:27 2015-08-28 10:27

jQuery, используя $.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]; 
10
ответ дан DanFromGermany 01 апр. '14 в 14:15 2014-04-01 14:15

Использование циклов с оператором деструктуризации и распространения ES6

Разрушение и использование оператора распространения оказались весьма полезными для новичков в ES6 как более удобочитаемые/эстетичные, хотя некоторые ветераны javascript могут посчитать это грязным, юниоры или некоторые другие люди могут найти его полезным.

Следующие примеры будут использовать for...of оператора и метода .forEach .

Примеры 6, 7 и 8 могут использоваться с любыми функциональными циклами, такими как .map , .filter , .reduce , .sort , .every , .some , для получения дополнительной информации об этих методах проверьте объект Array .

Пример 1: Нормально for...of цикла - здесь нет хитростей.

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

Пример 3: Цикл с key и value

 let arrWithObjects = [{ name: 'Jon', age: 32 }, { name: 'Elise', age: 33 } ]; for (let { name, age: aliasForAge } of arrWithObjects) { console.log(name, aliasForAge); } 

Пример 5: Получить глубокие свойства объекта того, что вам нужно

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

Пример 7: Используется ли пример 4 с .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); }); 
6
ответ дан darklightcode 09 окт. '18 в 23:19 2018-10-09 23:19

Ближе всего к вашей идее будет использовать Array.forEach() , который принимает функцию clojure, которая будет выполнена для каждого элемента массива.

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

Другим жизнеспособным способом было бы использовать Array.map() , который работает одинаково, но также и mutates каждый элемент и возвращает его так:

 var myArray = [1, 2, 3]; myArray = myArray.map( (item) => { return item + 1; } ); console.log(myArray); // [2, 3, 4] 
6
ответ дан Ante Jablan Adamović 09 нояб. '17 в 18:31 2017-11-09 18:31

Синтаксис лямбда обычно не работает в IE 10 или ниже.

Обычно я использую

 [].forEach.call(arrayName,function(value,index){ console.log("value of the looped element" + value); console.log("index of the looped element" + index); }); If you are a jQuery Fan and already have a jQuery file running, you should reverse the positions of the index and value parameters $("#ul>li").each(function(**index,value**){ console.log("value of the looped element" + value); console.log("index of the looped element" + index); }); 
5
ответ дан Murtuza Husain 11 нояб. '17 в 9:16 2017-11-11 09:16

Вы можете вызвать forEach Как это:

 let Array = [1,3,2]; theArray.forEach((element)=>{ // use the element of the array console.log(element) } 

элемент будет иметь значение каждого индекса от 0 до длины массива.

Fazit:

 1 3 2 

Explaination:

forEach находится в классе прототипов. вы также можете назвать это какArray.prototype.forEach(...);

прототип: https://hackernoon.com/prototypes-in-javascript-5bba2990e04b

Вы также можете изменить массив таким образом:

 for(let i=0;i<theArray.length;i++){ console.log(i); //i will have the value of each index } 
4
ответ дан Nouman Dilshad 17 июля '18 в 15:30 2018-07-17 15:30

Zusammenfassung:

При повторении массива мы часто можем достичь одной из следующих целей:

  1. Мы хотим перебрать массив и создать новый массив:

    Array.prototype.map

  2. Мы хотим перебрать массив и не создавать новый массив:

    Array.prototype.forEach

    for..of циклы

В JS существует множество способов достижения обеих этих целей. Однако некоторые из них более примитивны, чем другие. Ниже вы можете найти некоторые общепринятые методы (наиболее удобные imo) для выполнения итерации массива в javascript.

Создание нового массива: Map

map() - это функция, расположенная на Array.prototype которая может преобразовывать каждый элемент массива и затем возвращает новый массив. map() принимает в качестве аргумента функцию обратного вызова и работает следующим образом:

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

Точно так же, как функция map , обратный вызов forEach предоставляет в качестве второго аргумента номер индекса текущей итерации. Также третий аргумент предоставляет массив, на который был вызван forEach .

for..of элементы, используя

Цикл for..of циклы через каждый элемент массива (или любой другой итерируемый объект). Он работает следующим образом:

 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); } 
2
ответ дан Willem van der Veen 08 сент. '18 в 10:55 2018-09-08 10:55
 var a = ["car", "bus", "truck"] a.forEach(function(item, index) { console.log("Index" + index); console.log("Element" + item); }) 
1
ответ дан John 11 янв. '18 в 21:03 2018-01-11 21:03

Если у вас массивный массив, вы должны использовать iterators чтобы получить некоторую эффективность. Итераторы являются свойством некоторых сборников JavaScript (таких как Map , Set , String , Array ). Даже для for..of использования iterator под капотом.

Итераторы повышают эффективность, позволяя вам потреблять элементы в списке по одному, как если бы они были потоком. Что делает специальный итератор особенным, так это то, как он перемещается по коллекции. Другие циклы должны загружать всю коллекцию спереди, чтобы перебирать ее, тогда как итератору нужно знать только текущую позицию в коллекции.

Вы получаете доступ к текущему элементу, вызывая next метод итераторов. Следующий метод вернет value текущего элемента и boolean чтобы указать, когда вы достигли конца коллекции. Ниже приведен пример создания итератора из массива.

Преобразуйте свой обычный массив в итератор, используя метод values() следующим образом:

Symbol.iterator следующим образом: 

iterator следующим образом: 

for..in в этом случае, потому что вместо значений он работает с ключами. 

Вы можете прочитать больше о iteration protocol здесь .

1
ответ дан BlackBeard 06 июля '18 в 10:11 2018-07-06 10:11

Если вы хотите сохранить функциональность своего кода, используйте map:

 theArray.map(instance => do_something); 

Таким образом, вы создадите новый массив для будущей работы и пропустите любой нежелательный побочный эффект.

0
ответ дан alejoko 02 февр. '19 в 18:13 2019-02-02 18:13

Если вы хотите использовать forEach() , это будет выглядеть так -

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

Если вы хотите использовать for() , это будет выглядеть как -

 for(let idx = 0; idx < theArray.length; idx++){ let element = theArray[idx]; console.log(element); } 
0
ответ дан Harunur Rashid 30 мая '18 в 12:05 2018-05-30 12:05

Я пришел с питона, и я нашел этот путь намного яснее.
theArray - массив, экземпляр - элемент массива.

 for(let instance of theArray) { console.log("The instance",instance); } 

oder

 for( instance in theArray) { console.log("The instance",instance); } 

сравнить с:

 theArray.forEach(function(instance) { console.log(instance); }); 

но в конце дня оба делают одно и то же

0
ответ дан Peko Chan 12 дек. '18 в 14:06 2018-12-12 14:06
  • 1
  • 2

Другие вопросы по меткам или Задайте вопрос