Pętla w tablicy w JavaScript

3142

W Javie można użyć forpętli do przechodzenia przez obiekty w tablicy w następujący sposób:

String[] myStringArray = {"Hello", "World"};
for (String s : myStringArray)
{
    // Do something
}

Czy możesz zrobić to samo w JavaScript?

Mark Szymański
źródło
5
Ok, więc jestem trochę zdezorientowany, czy można korzystać z rozszerzonej pętli for podczas uzyskiwania dostępu do obiektów? I użyć sekwencyjnego do wypełnienia jednego? Czy to jest poprawne?
Mark Szymanski
45
nie, to naprawdę proste, obiekty tablicowe mają indeksy numeryczne, więc chcesz iterować nad tymi indeksami w kolejności numerycznej, sekwencyjna pętla zapewnia, że ulepszona for-in pętla wylicza właściwości obiektu, bez określonej kolejności, a także wylicza właściwości odziedziczone. .. do iteracji po tablicach zawsze zalecane są sekwencyjne pętle ...
CMS
2
powiązane - stackoverflow.com/questions/5349425/…
jondavidjohn
6
jsben.ch/#/Q9oD5 <= Oto test porównawczy wielu rozwiązań do zapętlania tablic
EscapeNetscape,
3
@CMS Nie, to nie jest naprawdę proste. To jest naprawdę proste w każdym innym języku. Jest absurdalnie skomplikowany w JS, w którym masz ini ofktóry może być używany i robić różne rzeczy. Następnie masz forEachi brzydką i irytującą pętlę opartą na indeksie. Każdy inny współczesny język sprawia, że ​​przeglądanie kolekcji jest łatwe i proste, bez niespodzianek i zamieszania. JS też może, ale nie robi.
jpmc26

Odpowiedzi:

3955

Masz kilka opcji:

1. forPętla sekwencyjna :

var myStringArray = ["Hello","World"];
var arrayLength = myStringArray.length;
for (var i = 0; i < arrayLength; i++) {
    console.log(myStringArray[i]);
    //Do something
}

Plusy

  • Działa w każdym środowisku
  • Możesz używać breaki continuesterować przepływem instrukcji

Cons

2. Array.prototype.forEach

Specyfikacja ES5 wprowadziła wiele korzystnych metod macierzy, jedną z nich Array.prototype.forEachi daje nam zwięzły sposób na iterację po tablicy:

const array = ["one", "two", "three"]
array.forEach(function (item, index) {
  console.log(item, index);
});

Mając prawie dziesięć lat od momentu napisania specyfikacji ES5 (grudzień 2009 r.), Została zaimplementowana przez prawie wszystkie nowoczesne silniki w środowiskach stacjonarnych, serwerowych i mobilnych, więc można z nich bezpiecznie korzystać.

Dzięki składni funkcji strzałek ES6 jest jeszcze bardziej zwięzły:

array.forEach(item => console.log(item));

Funkcje strzałek są również szeroko implementowane, chyba że planujesz wspierać starożytne platformy (np. IE11); jesteś również bezpieczny.

Plusy

  • Bardzo krótki i zwięzły.
  • Deklaracyjny

Cons

  • Nie można użyć break/continue

Zwykle można zastąpić konieczność breakwyjścia z pętli imperatywnych, filtrując elementy tablicy przed iteracją, na przykład:

array.filter(item => item.condition < 10)
     .forEach(item => console.log(item))

Pamiętaj, że jeśli iterujesz tablicę, aby zbudować z niej kolejną tablicę , powinieneś użyć map, widziałem ten anty-wzór tyle razy.

Anty-wzór:

const numbers = [1,2,3,4,5], doubled = [];

numbers.forEach((n, i) => { doubled[i] = n * 2 });

Właściwy przypadek użycia mapy :

const numbers = [1,2,3,4,5];
const doubled = numbers.map(n => n * 2);

console.log(doubled);

Ponadto, jeśli próbujesz zredukować tablicę do wartości, na przykład chcesz zsumować tablicę liczb, powinieneś użyć metody zmniejszania .

Anty-wzór:

const numbers = [1,2,3,4,5];
const sum = 0;
numbers.forEach(num => { sum += num });

Prawidłowe stosowanie redukcji :

const numbers = [1,2,3,4,5];
const sum = numbers.reduce((total, n) => total + n, 0);

console.log(sum);

3. for-ofOświadczenie ES6

Standard ES6 wprowadza koncepcję obiektów iterowalnych i definiuje nową konstrukcję do przeszukiwania danych, for...ofoświadczenie.

Ta instrukcja działa dla każdego rodzaju iterowalnego obiektu, a także dla generatorów (każdego obiektu, który ma [Symbol.iterator]właściwość).

Obiekty tablic są z definicji wbudowanymi iterowaniami w ES6, więc możesz na nich użyć tej instrukcji:

let colors = ['red', 'green', 'blue'];
for (const color of colors){
    console.log(color);
}

Plusy

  • Może iterować wiele różnych obiektów.
  • Może używać normalnych instrukcji kontroli przepływu ( break/ continue).
  • Przydatne do iteracji szeregowo asynchronicznych wartości.

Cons

Nie używaj for...in

@zipcodeman sugeruje użycie for...ininstrukcji, ale w przypadku tablic iteracyjnych for-innależy unikać tej instrukcji, która służy do wyliczenia właściwości obiektu.

Nie należy go używać do obiektów podobnych do tablicy, ponieważ:

  • Kolejność iteracji nie jest gwarantowana; indeksy tablicowe nie mogą być odwiedzane w kolejności numerycznej.
  • Dziedziczone właściwości również są wyliczane.

Druga kwestia polega na tym, że może sprawić wiele problemów, na przykład jeśli rozszerzysz Array.prototypeobiekt o metodę, właściwość ta zostanie również wyliczona.

Na przykład:

Array.prototype.foo = "foo!";
var array = ['a', 'b', 'c'];

for (var i in array) {
    console.log(array[i]);
}

Powyższy kod będzie zawierał logi „a”, „b”, „c” i „foo!”.

Jest to szczególnie problem, jeśli korzystasz z biblioteki, która w dużym stopniu opiera się na rozszerzaniu natywnych prototypów (na przykład MooTools).

for-inOświadczenie powiedziałem wcześniej jest tam, aby wyliczyć właściwości obiektu, na przykład:

var obj = {
    "a": 1,
    "b": 2,
    "c": 3
};

for (var prop in obj) {
    if (obj.hasOwnProperty(prop)) { 
        // or if (Object.prototype.hasOwnProperty.call(obj,prop)) for safety...
        console.log("prop: " + prop + " value: " + obj[prop])
    }
}

W powyższym przykładzie hasOwnPropertymetoda pozwala wyliczyć tylko własne właściwości , to jest to, tylko właściwości, które fizycznie ma obiekt, bez dziedziczonych właściwości.

Poleciłbym przeczytać następujący artykuł:

CMS
źródło
20
To jest powód (przez CMS go samodzielnie) stackoverflow.com/questions/1885317/…
OscarRyz
14
@DoubleGras, myślę, że to opinia, która nie jest podzielana przez wszystkich. Zobacz: stackoverflow.com/questions/5752906/… lub groups.google.com/forum/?fromgroups#!topic/jsmentors/…
Matthijs Wessels
2
Każdy, kto myśli, że potrzebujesz buforować długość ... Proszę zobaczyć moją odpowiedź, nie musisz nawet uzyskiwać do niej dostępu raz, nie mówiąc już o buforowaniu: for (var i = 0, item; item = myStringArray [i]; i ++) {/ * użyj elementu tutaj * /}
Stijn de Witt
13
@StijndeWitt Nie, bo to przerw, jeśli masz jakieś „falsey” wartości w tablicy: false, undefined, 0, "", NaN.
Phrogz
5
jsperf.com/caching-array-length/4 Oto test, aby sprawdzić, czy warto buforować długość tablicy w pętli JavaScript
Enrico
1113

Tak, zakładając, że twoja implementacja zawiera for...of funkcję wprowadzoną w ECMAScript 2015 (wydanie „Harmony”)… co jest całkiem bezpiecznym założeniem w dzisiejszych czasach.

Działa to tak:

// REQUIRES ECMASCRIPT 2015+
var s, myStringArray = ["Hello", "World"];
for (s of myStringArray) {
  // ... do something with s ...
}

Albo jeszcze lepiej, ponieważ ECMAScript 2015 zapewnia również zmienne o zasięgu blokowym:

// REQUIRES ECMASCRIPT 2015+
const myStringArray = ["Hello", "World"];
for (const s of myStringArray) {
  // ... do something with s ...
}
// s is no longer defined here

(Zmienna sjest inna dla każdej iteracji, ale nadal może być zadeklarowana constw ciele pętli, o ile nie jest tam modyfikowana).

Uwaga na rzadkie tablice: tablica w JavaScript może tak naprawdę nie przechowywać tylu elementów, ile zgłasza length; podana liczba jest po prostu o jeden większa niż najwyższy wskaźnik, pod którym przechowywana jest wartość. Jeśli tablica zawiera mniej elementów niż wskazuje jej długość, mówi się, że jest rzadka . Na przykład, całkowicie uzasadnione jest posiadanie tablicy z elementami tylko o indeksach 3, 12 i 247; lengthtakiej tablicy jest zgłaszane jako 248, choć w rzeczywistości jest tylko 3 przechowywania wartości. Jeśli spróbujesz uzyskać dostęp do elementu w dowolnym innym indeksie, tablica będzie miała undefinedtam wartość. Kiedy więc chcesz „zapętlić” tablicę, musisz odpowiedzieć na pytanie: czy chcesz zapętlić cały zakres wskazany przez jego długość i procesundefineds dla brakujących elementów, czy chcesz przetwarzać tylko te elementy, które faktycznie są obecne? Istnieje wiele aplikacji dla obu podejść; to zależy tylko od tego, do czego używasz tablicy.

Jeśli wykonasz iterację po tablicy za pomocą for... of, treść pętli jest wykonywana lengthrazy, a zmienna sterująca pętli jest ustawiana undefinedna dowolne elementy, które faktycznie nie występują w tablicy. W zależności od szczegółów kodu „zrób coś z” takie zachowanie może być tym, czego chcesz, ale jeśli nie, powinieneś zastosować inne podejście.

Oczywiście, niektórzy deweloperzy nie mają wyboru, aby użyć innego podejścia tak, ponieważ z jakiegoś powodu są one kierowane na wersję JavaScript, który nie obsługuje jeszcze for... of.

Tak długo, jak implementacja JavaScript jest zgodna z poprzednią edycją specyfikacji ECMAScript (która wyklucza na przykład wersje Internet Explorera przed 9), możesz użyć Array#forEachmetody iteratora zamiast pętli. W takim przypadku przekazujesz funkcję, która ma zostać wywołana dla każdego elementu w tablicy:

var myStringArray = [ "Hello", "World" ];
myStringArray.forEach( function(s) { 
     // ... do something with s ...
} );

W przeciwieństwie do for... of, .forEachwywołuje funkcję tylko dla elementów, które faktycznie są obecne w tablicy. Jeśli przejdzie przez naszą hipotetyczną tablicę z trzema elementami i długością 248, wywoła funkcję tylko trzy razy, a nie 248 razy. Rozróżnia także brakujące elementy od elementów, które są ustawione undefined; w drugim przypadku nadal wywoła funkcję, przekazując undefinedjako argument. Jeśli jest to w jaki sposób chcesz obsługiwać macierze rzadkie, .forEachmoże być droga, nawet jeśli obsługuje tłumacza for... of.

Ostatnią opcją, która działa we wszystkich wersjach JavaScript, jest wyraźna pętla zliczania . Po prostu liczysz od 0 do jednego mniej niż długość i używasz licznika jako indeksu. Podstawowa pętla wygląda następująco:

var i, s, myStringArray = [ "Hello", "World" ], len = myStringArray.length;
for (i=0; i<len; ++i) {
  s = myStringArray[i];
  // ... do something with s ...
}

Zaletą tego podejścia jest to, że możesz wybrać sposób obsługi rzadkich tablic; Powyższy kod będzie działał ciało pełne pętli lengthrazy, z szestawem do undefinedwszelkich brakujących elementów, podobnie jak for.. of. Jeśli zamiast tego chcesz obsługiwać tylko faktycznie obecne elementy rzadkiej tablicy, .forEachmożesz dodać prosty intest do indeksu:

var i, s, myStringArray = [ "Hello", "World" ], len = myStringArray.length;
for (i=0; i<len; ++i) {
  if (i in myStringArray) {
    s = myStringArray[i];
    // ... do something with s ...
  }
}

Przypisanie wartości długości zmiennej lokalnej (w przeciwieństwie do włączenia pełnego myStringArray.lengthwyrażenia w warstwie pętli) może mieć znaczącą różnicę w wydajności, ponieważ pomija wyszukiwanie właściwości za każdym razem; przy użyciu Rhino na moim komputerze, przyspieszenie wynosi 43%.

Możesz zobaczyć buforowanie długości wykonane w klauzuli inicjalizacji pętli, jak poniżej:

var i, len, myStringArray = [ "Hello", "World" ];
for (len = myStringArray.length, i=0; i<len; ++i) {

Wyraźna pętla zliczania oznacza również, że masz dostęp do indeksu każdej wartości, jeśli chcesz. Indeks jest także przekazywany jako dodatkowy parametr do funkcji, którą przekazujesz forEach, więc możesz uzyskać do niego dostęp również w ten sposób:

myStringArray.forEach( function(s, i) {
   // ... do something with s and i ...
});

for... ofnie daje indeksu powiązanego z każdym obiektem, ale dopóki obiekt, który iterujesz, jest w rzeczywistości Array( for.. ofdziała dla innych typów iterowalnych, które mogą nie mieć tej metody), możesz użyć tablicy Metoda #entries , aby zmienić ją na tablicę par [indeks, pozycja], a następnie iterować:

for (const [i, s] of myStringArray.entries()) {
  // ... do something with s and i ...
}

for... inskładnia wspomniano przez innych jest dla zapętlenie nad właściwości obiektu; ponieważ tablica w JavaScript jest tylko obiektem z numerycznymi nazwami właściwości (i automatycznie aktualizowaną lengthwłaściwością), teoretycznie można za jej pomocą łączyć się z tablicą. Problem polega jednak na tym, że nie ogranicza się on do liczbowych wartości właściwości (pamiętaj, że nawet metody są w rzeczywistości właściwościami, których wartością jest zamknięcie), ani nie ma gwarancji, że będą iterować w stosunku do tych w kolejności numerycznej. Dlatego składnia for... niein powinna być używana do zapętlania tablic.

Mark Reed
źródło
21
Zauważ, że niektórzy interpretatorzy (np. V8) automatycznie buforują długość tablicy, jeśli kod jest wywoływany wystarczającą liczbę razy i wykrywa, że ​​długość nie jest modyfikowana przez pętlę. Chociaż buforowanie długości jest wciąż przyjemne, może nie zapewniać zwiększenia prędkości, gdy kod jest wywoływany wystarczająco często, aby faktycznie coś zmienić.
Phrogz
2
@ mark-reed Czy możesz wyjaśnić, dlaczego użyłeś i in myStringArraytego przykładu? Jak to może być fałsz?
Denis V
2
@DenisV: false. a=[1,2,3,4]; delete a[2]; for (j in a) { console.log(j); } wyniki 0, 1, 3 i 4. a.lengthto wciąż 5.
Mark Reed
1
Nie sugeruję for j in a. Wykazuję, że inczek nie jest zbędny, tak jak twierdziłeś, pokazując wszystkie indeksy i pokazując, że jest jeden między 0 i length-1że go nie ma. Mógłbym też właśnie wydrukować 2 in a, co jest rzeczywiście false, pomimo faktu, że powiedziałeś, że to niemożliwe.
Mark Reed,
2
@GrijeshChauhan - poprawnie. Na przykład IE w wersji 8 nie obsługuje tego. Zobacz to pytanie .
Mark Reed
442

Możesz użyć map, która jest funkcjonalną techniką programowania, która jest również dostępna w innych językach, takich jak Python i Haskell .

[1,2,3,4].map( function(item) {
     alert(item);
})

Ogólna składnia to:

array.map(func)

Ogólnie rzecz biorąc func, wziąłby jeden parametr, który jest elementem tablicy. Ale w przypadku JavaScript może on przyjąć drugi parametr, który jest indeksem elementu, i trzeci parametr, który jest samą tablicą.

Zwracana wartość array.mapto kolejna tablica, więc możesz użyć jej w następujący sposób:

var x = [1,2,3,4].map( function(item) {return item * 10;});

A teraz x jest [10,20,30,40].

Nie musisz pisać funkcji bezpośrednio. Może to być osobna funkcja.

var item_processor = function(item) {
      // Do something complicated to an item
}

new_list = my_list.map(item_processor);

co byłoby swego rodzaju odpowiednikiem:

 for (item in my_list) {item_processor(item);}

Tyle że nie dostaniesz new_list.

hasen
źródło
7
Nie, ale może być mocniejszy. sprawdź to: joelonsoftware.com/items/2006/08/01.html
hasen
97
Ten konkretny przykład jest prawdopodobnie lepiej zaimplementowany przy użyciu Array.forEach. mapsłuży do generowania nowej tablicy.
harto
21
@hasen, Array.prototype.mapmetoda jest częścią standardu ECMAScript 5. edycja, nie jest jeszcze dostępna we wszystkich implementacjach (np. jej brak w IE), również do iteracji po tablicy Myślę, że Array.prototype.forEachmetoda jest bardziej semantycznie poprawna ... proszę również nie t zasugerować oświadczenie for-in, zobacz moją odpowiedź, aby uzyskać więcej informacji :)
CMS
3
Różnica między forEachi mappolega na tym, że ten pierwszy nie zwraca wyników iteracji. map(czasami aka collect, ale bardzo różni się od apply) jest wyraźnie przekształcenie każdego elementu tablicy w odpowiedni wynik; jest to mapowanie 1 do 1 , stąd nazwa. Jest to część całej rodziny operacji, które obejmują reduce(która daje pojedynczy wynik z całej tablicy) i filter(która tworzy podzbiór oryginalnej tablicy) i tak dalej. Podczas gdy forEachrobi coś z każdym elementem, semantyka nie jest określona.
Mark Reed,
4
Oddaj głos, ponieważ jeśli tak naprawdę nie mapujesz, to użycie [] .map jest mylące. [] .forEach ma sens semantyczny i przekazuje te same trzy argumenty do funkcji.
gengkev
120

W JavaScript nie zaleca się przechodzenia przez tablicę za pomocą pętli for-in, ale lepiej jest użyć forpętli, takiej jak:

for(var i=0, len=myArray.length; i < len; i++){}

Jest również zoptymalizowany („buforowanie” długości tablicy). Jeśli chcesz dowiedzieć się więcej, przeczytaj mój post na ten temat .

sebarmeli
źródło
2
myArray.forEach (function (obj) {}); jest nadal najlepszy
Jan Sverre
drobna poprawa: możesz użyć ++izamiasti++
roberkules,
14
++ito
oldschoolowa
6
Musisz być ostrożny używając tej pętli. Zacząłem go używać i miałem trudny do wyśledzenia błąd z powodu jednego błędu, który popełniłem. Jeśli zagnieżdżycie dwie takie pętle: jsfiddle.net/KQwmL/1 . Musisz zachować ostrożność, aby nazwać zmienną w dwóch pętlach inaczej, w przeciwnym razie druga pętla nadpisze pierwszą zmienną.
Rui Marques
1
Rui Marques - możesz nazwać swoją zmienną i_stoplub i_endzamiast niej len. Jest tak samo czytelny (jeśli nie bardziej!) I naturalnie unikniesz tego rodzaju problemów (ponieważ twoja druga pętla dostanie np j_stop.).
Chip Hogg
118

for (lets of myStringArray) {

(Bezpośrednio odpowiadając na twoje pytanie: teraz możesz!)

Większość innych odpowiedzi jest poprawnych, ale nie wspominają (od tego momentu), że ECMA Script  6  2015 wprowadza nowy mechanizm wykonywania iteracji, for..ofpętlę.

Ta nowa składnia jest najbardziej eleganckim sposobem na iterację tablicy w javascript (o ile nie potrzebujesz indeksu iteracji).

Obecnie działa z Firefox 13+, Chrome 37+ i nie działa natywnie z innymi przeglądarkami (patrz kompatybilność przeglądarki poniżej). Na szczęście mamy kompilatory JS (takie jak Babel ), które pozwalają nam dziś korzystać z funkcji nowej generacji.

Działa również na węźle (przetestowałem go na wersji 0.12.0).

Iterowanie tablicy

// You could also use "let" instead of "var" for block scope.
for (var letter of ["a", "b", "c"]) { 
   console.log(letter); 
}

Iterowanie tablicy obiektów

var band = [
  {firstName : 'John', lastName: 'Lennon'}, 
  {firstName : 'Paul', lastName: 'McCartney'}
];

for(var member of band){
  console.log(member.firstName + ' ' + member.lastName); 
}

Iterowanie generatora:

(przykład wyodrębniony z https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of )

function* fibonacci() { // a generator function
  let [prev, curr] = [1, 1];
  while (true) {
    [prev, curr] = [curr, prev + curr];
    yield curr;
  }
}

for (let n of fibonacci()) {
  console.log(n);
  // truncate the sequence at 1000
  if (n >= 1000) {
    break;
  }
}

Tabela kompatybilności: http://kangax.github.io/es5-compat-table/es6/#For..of loop

Spec: http://wiki.ecmascript.org/doku.php?id=harmony:iterators

}

Marlon Bernardes
źródło
Jeśli używasz ES6, sugerowałbym const szamiastvar s
joeytwiddle
W moich testach na dużych tablicach użycie var s of arrjest prawie dwukrotnie (1,9x) czas wykonania w porównaniu do użycia prostego licznika pętli for i pobierania elementów według indeksu w nodejs
theferrit32
Dlaczego te dziwne rzeczy w pierwszej i ostatniej linii?
Peter Mortensen
91

Opera, Safari, Firefox i Chrome udostępniają teraz zestaw ulepszonych metod Array do optymalizacji wielu popularnych pętli.

Możesz nie potrzebować wszystkich, ale mogą być bardzo przydatne lub byłyby, gdyby każda przeglądarka je obsługiwała.

Mozilla Labs opublikowało algorytmy, których używają i WebKit , abyś mógł je dodać samodzielnie.

Filtr zwraca tablicę elementów, które spełniają określone warunki lub testy.

każdy zwraca wartość true, jeśli każdy element tablicy przejdzie test.

niektóre zwracają prawdę, jeśli w ogóle zdadzą test.

forEach uruchamia funkcję na każdym elemencie tablicy i niczego nie zwraca.

mapa jest jak forEach, ale zwraca tablicę wyników operacji dla każdego elementu.

Wszystkie te metody przyjmują funkcję dla pierwszego argumentu i mają opcjonalny drugi argument, który jest obiektem, którego zakres chcesz narzucić członkom tablicy podczas ich przechodzenia przez funkcję.

Zignoruj ​​to, aż będziesz go potrzebować.

indexOf i lastIndexOf znajdują odpowiednią pozycję pierwszego lub ostatniego elementu, która dokładnie pasuje do jego argumentu.

(function(){
    var p, ap= Array.prototype, p2={
        filter: function(fun, scope){
            var L= this.length, A= [], i= 0, val;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        val= this[i];
                        if(fun.call(scope, val, i, this)){
                            A[A.length]= val;
                        }
                    }
                    ++i;
                }
            }
            return A;
        },
        every: function(fun, scope){
            var L= this.length, i= 0;
            if(typeof fun== 'function'){
                while(i<L){
                    if(i in this && !fun.call(scope, this[i], i, this))
                        return false;
                    ++i;
                }
                return true;
            }
            return null;
        },
        forEach: function(fun, scope){
            var L= this.length, i= 0;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        fun.call(scope, this[i], i, this);
                    }
                    ++i;
                }
            }
            return this;
        },
        indexOf: function(what, i){
            i= i || 0;
            var L= this.length;
            while(i< L){
                if(this[i]=== what)
                    return i;
                ++i;
            }
            return -1;
        },
        lastIndexOf: function(what, i){
            var L= this.length;
            i= i || L-1;
            if(isNaN(i) || i>= L)
                i= L-1;
            else
                if(i< 0) i += L;
            while(i> -1){
                if(this[i]=== what)
                    return i;
                --i;
            }
            return -1;
        },
        map: function(fun, scope){
            var L= this.length, A= Array(this.length), i= 0, val;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        A[i]= fun.call(scope, this[i], i, this);
                    }
                    ++i;
                }
                return A;
            }
        },
        some: function(fun, scope){
            var i= 0, L= this.length;
            if(typeof fun== 'function'){
                while(i<L){
                    if(i in this && fun.call(scope, this[i], i, this))
                        return true;
                    ++i;
                }
                return false;
            }
        }
    }
    for(p in p2){
        if(!ap[p])
            ap[p]= p2[p];
    }
    return true;
})();
Kennebec
źródło
1
Dodanie: IE obsługuje forEach od wersji 9, patrz forEach Method MSDN
rwitzel 17.04.15
75

Wprowadzenie

Od czasu studiów studiowałem w Javie, JavaScript, Pascal, ABAP , PHP, Progress 4GL, C / C ++ i prawdopodobnie w kilku innych językach, o których nie mogę teraz myśleć.

Chociaż wszystkie mają swoje osobliwości językowe, każdy z tych języków ma wiele takich samych podstawowych pojęć. Takie pojęcia obejmują procedury / funkcje IF, FOR-statements, WHILE-loops i -loops.


Tradycyjna forpętla

Tradycyjna forpętla składa się z trzech elementów:

  1. Inicjalizacja: wykonywana przed pierwszym uruchomieniem bloku look
  2. Warunek: sprawdza warunek za każdym razem przed wykonaniem bloku pętli i kończy pętlę, jeśli jest fałszem
  3. Myśl następująca: wykonywana za każdym razem po wykonaniu bloku pętli

Te trzy elementy są oddzielone od siebie ;symbolem. Treść dla każdego z tych trzech składników jest opcjonalna, co oznacza, że ​​następująca jest najbardziej minimalna formożliwa pętla:

for (;;) {
    // Do stuff
}

Oczywiście, musisz dołączyć if(condition === true) { break; } lub if(condition === true) { return; }gdzieś wewnątrz tej forpętli, aby przestała działać.

Zwykle jednak inicjacja służy do deklarowania indeksu, warunek służy do porównania tego indeksu z wartością minimalną lub maksymalną, a przemyślenie służy do zwiększenia indeksu:

for (var i = 0, length = 10; i < length; i++) {
    console.log(i);
}

Używanie tradycyjnej forpętli do przechodzenia przez tablicę

Tradycyjny sposób przechodzenia przez tablicę jest następujący:

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

Lub, jeśli wolisz zapętlać wstecz, wykonaj następujące czynności:

for (var i = myArray.length - 1; i > -1; i--) {
    console.log(myArray[i]);
}

Istnieje jednak wiele odmian, na przykład ta:

for (var key = 0, value = myArray[key], length = myArray.length; key < length; value = myArray[++key]) {
    console.log(value);
}

...albo ten...

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

...albo ten:

var key = 0, value;
for (; value = myArray[key++];){
    console.log(value);
}

To, co działa najlepiej, zależy w dużej mierze zarówno od osobistego gustu, jak i konkretnego przypadku zastosowania, który wdrażasz.

Pamiętaj, że każda z tych odmian jest obsługiwana przez wszystkie przeglądarki, w tym bardzo bardzo stare!


whilepętli

Jedną alternatywą dla forpętli jest whilepętla. Aby przejść przez tablicę, możesz to zrobić:

var key = 0;
while(value = myArray[key++]){
    console.log(value);
}

Podobnie jak tradycyjne forpętle, whilepętle są obsługiwane nawet przez najstarszą przeglądarkę.

Pamiętaj również, że pętla while może być przepisana jako forpętla. Na przykład whilepowyższa pętla zachowuje się dokładnie tak samo, jak ta forpętla:

for(var key = 0; value = myArray[key++];){
    console.log(value);
}

For...in i for...of

W JavaScript możesz także to zrobić:

for (i in myArray) {
    console.log(myArray[i]);
}

Należy to jednak stosować ostrożnie, ponieważ nie zachowuje się tak samo jak tradycyjna forpętla we wszystkich przypadkach i należy wziąć pod uwagę potencjalne skutki uboczne. Zobacz: Dlaczego używanie „dla ... w” z iteracją tablicy jest złym pomysłem? po więcej szczegółów.

Alternatywą dla for...injest teraz także for...of. Poniższy przykład pokazuje różnicę między for...ofpętlą a for...inpętlą:

var myArray = [3, 5, 7];
myArray.foo = "hello";

for (var i in myArray) {
  console.log(i); // logs 0, 1, 2, "foo"
}

for (var i of myArray) {
  console.log(i); // logs 3, 5, 7
}

Ponadto należy wziąć pod uwagę, że żadna wersja programu Internet Explorer nie obsługuje for...of( Edge 12+ obsługuje), a to for...inwymaga co najmniej Internet Explorera 10.


Array.prototype.forEach()

Alternatywą dla opcji for-loops jest Array.prototype.forEach()użycie następującej składni:

myArray.forEach(function(value, key, myArray) {
    console.log(value);
});

Array.prototype.forEach() jest obsługiwany przez wszystkie nowoczesne przeglądarki, a także Internet Explorer 9 i nowsze wersje.


Biblioteki

Wreszcie, wiele bibliotek narzędzi ma również swoje własne foreachodmiany. AFAIK, trzy najpopularniejsze to:

jQuery.each(), w jQuery :

$.each(myArray, function(key, value) {
    console.log(value);
});

_.each(), w Underscore.js :

_.each(myArray, function(value, key, myArray) {
    console.log(value);
});

_.forEach(), w Lodash.js :

_.forEach(myArray, function(value, key) {
    console.log(value);
});
John Slegers
źródło
68

Użyj pętli while ...

var i=0, item, items = ['one','two','three'];
while(item = items[i++]){
    console.log(item);
}

logi: „jeden”, „dwa”, „trzy”

A dla odwrotnej kolejności jeszcze bardziej wydajna pętla

var items = ['one','two','three'], i = items.length;
while(i--){
    console.log(items[i]);
}

logi: „trzy”, „dwa”, „jeden”

Lub klasyczna forpętla

var items = ['one','two','three']
for(var i=0, l = items.length; i < l; i++){
    console.log(items[i]);
}

logi: „jeden”, „dwa”, „trzy”

Odniesienie: http://www.sitepoint.com/google-closure-how-not-to-write-javascript/

Timo Huovinen
źródło
21
Pierwszy przykład składni „while” nie zadziała, jeśli którykolwiek z elementów tablicy jest fałszywy.
Chris Cooper
2
... a ta pętla while jest równoważna z: for (var i = 0, item; item = items [i]; i ++), co eliminuje potrzebę wcześniejszego zadeklarowania zmiennych indeksu i item ...
Stijn de Witt
39

Jeśli chcesz zwięzły sposób napisać szybką pętlę i możesz iterować w odwrotnej kolejności:

for (var i=myArray.length;i--;){
  var item=myArray[i];
}

Ma to tę zaletę, że buforuje długość (podobną for (var i=0, len=myArray.length; i<len; ++i)i niepodobną for (var i=0; i<myArray.length; ++i)), a jednocześnie jest mniej znaków do wpisania.

Są nawet chwile, kiedy powinieneś iterować w odwrotnej kolejności, na przykład podczas iteracji nad aktywną listą NodeList, na której planujesz usuwanie elementów z DOM podczas iteracji.

Phrogz
źródło
16
Dla osób, które nie rozumieją, co jest tak genialne: Wyrażenie i-- jest najpierw oceniane i pozwala na kontynuowanie pętli, gdy nie jest fałszem ... Następnie licznik jest zmniejszany. Gdy tylko osiągnę zero, wyłamie się z pętli, ponieważ zero jest wartością fałszowania w Javascripcie.
Stijn de Witt
5
fałsz? Masz na myśli falsey. Trzymajmy się właściwej terminologii, aby uniknąć nieporozumień;)
Danwellman 27.04.13
4
Widziałem pojęcie falsish używane przez ludzi, których uważam za guru. Jeśli jest dla nich wystarczająco dobry, jest dla mnie wystarczająco dobry. Również rozczarowany, widząc, że mój komentarz, który jest rzeczywiście ontopyczny i dodaje wyjaśnienie / wgląd, otrzymuje 0 głosów pozytywnych, ale komentarz, który nitpicks na termin w moim komentarzu dostaje 4. Ach, to tylko kwestia priorytetów.
Stijn de Witt
„Buforowanie długości”? Długość jest zapisywana jako liczba całkowita w tablicy, nie jest mierzona przy każdym dostępie do niej. Kopiowanie wartości długości do innej zmiennej nie przynosi żadnej korzyści.
Mouscellaneous
1
@Mouscellaneous W dzisiejszych czasach na pewno nie ma; w poprzednich latach iteracja tablic JavaScript buforowanie długości po stronie JavaScript (zamiast sięgania po implementację) było wyraźnym zyskiem (przy mikrooptymalizacji). Na przykład for (var i=0,len=array.length;i<len;++i)była popularną, rozsądną pętlą do pisania.
Phrogz
36

Niektóre przypadki użycia pętli przez tablicę w funkcjonalnym sposobie programowania w JavaScript:

1. Po prostu przejdź przez tablicę

const myArray = [{x:100}, {x:200}, {x:300}];

myArray.forEach((element, index, array) => {
    console.log(element.x); // 100, 200, 300
    console.log(index); // 0, 1, 2
    console.log(array); // same myArray object 3 times
});

Uwaga: Array.prototype.forEach () nie jest ściśle funkcjonalnym sposobem, ponieważ funkcja, którą przyjmuje jako parametr wejściowy, nie powinna zwracać wartości, która w związku z tym nie może być uważana za funkcję czystą.

2. Sprawdź, czy którykolwiek z elementów tablicy ma pozytywny wynik testu

const people = [
    {name: 'John', age: 23}, 
    {name: 'Andrew', age: 3}, 
    {name: 'Peter', age: 8}, 
    {name: 'Hanna', age: 14}, 
    {name: 'Adam', age: 37}];

const anyAdult = people.some(person => person.age >= 18);
console.log(anyAdult); // true

3. Przekształć w nową tablicę

const myArray = [{x:100}, {x:200}, {x:300}];

const newArray= myArray.map(element => element.x);
console.log(newArray); // [100, 200, 300]

Uwaga: Metoda map () tworzy nową tablicę z wynikami wywołania podanej funkcji na każdym elemencie tablicy wywołującej.

4. Zsumuj określoną właściwość i oblicz jej średnią

const myArray = [{x:100}, {x:200}, {x:300}];

const sum = myArray.map(element => element.x).reduce((a, b) => a + b, 0);
console.log(sum); // 600 = 0 + 100 + 200 + 300

const average = sum / myArray.length;
console.log(average); // 200

5. Utwórz nową tablicę na podstawie oryginału, ale bez modyfikacji

const myArray = [{x:100}, {x:200}, {x:300}];

const newArray= myArray.map(element => {
    return {
        ...element,
        x: element.x * 2
    };
});

console.log(myArray); // [100, 200, 300]
console.log(newArray); // [200, 400, 600]

6. Policz liczbę każdej kategorii

const people = [
    {name: 'John', group: 'A'}, 
    {name: 'Andrew', group: 'C'}, 
    {name: 'Peter', group: 'A'}, 
    {name: 'James', group: 'B'}, 
    {name: 'Hanna', group: 'A'}, 
    {name: 'Adam', group: 'B'}];

const groupInfo = people.reduce((groups, person) => {
    const {A = 0, B = 0, C = 0} = groups;
    if (person.group === 'A') {
        return {...groups, A: A + 1};
    } else if (person.group === 'B') {
        return {...groups, B: B + 1};
    } else {
        return {...groups, C: C + 1};
    }
}, {});

console.log(groupInfo); // {A: 3, C: 1, B: 2}

7. Pobierz podzbiór tablicy na podstawie określonych kryteriów

const myArray = [{x:100}, {x:200}, {x:300}];

const newArray = myArray.filter(element => element.x > 250);
console.log(newArray); // [{x:300}] 

Uwaga: Metoda filter () tworzy nową tablicę ze wszystkimi elementami, które pomyślnie przejdą test zaimplementowany przez podaną funkcję.

8. Posortuj tablicę

const people = [
  { name: "John", age: 21 },
  { name: "Peter", age: 31 },
  { name: "Andrew", age: 29 },
  { name: "Thomas", age: 25 }
];

let sortByAge = people.sort(function (p1, p2) {
  return p1.age - p2.age;
});

console.log(sortByAge);

wprowadź opis zdjęcia tutaj

9. Znajdź element w tablicy

const people = [ {name: "john", age:23},
                {name: "john", age:43},
                {name: "jim", age:101},
                {name: "bob", age:67} ];

const john = people.find(person => person.name === 'john');
console.log(john);

wprowadź opis zdjęcia tutaj

Metoda Array.prototype.find () zwraca wartość pierwszego elementu w tablicy, który spełnia podaną funkcję testową.

Bibliografia

Yuci
źródło
30

Istnieje sposób, aby to zrobić, gdy masz bardzo niewielki ukryty zasięg w swojej pętli i eliminujesz dodatkowe zmienne.

var i = 0,
     item;

// note this is weak to sparse arrays or falsey values
for ( ; item = myStringArray[i++] ; ){ 
    item; // This is the string at the index.
}

Lub jeśli naprawdę chcesz uzyskać identyfikator i mieć naprawdę klasyczną forpętlę:

var i = 0,
    len = myStringArray.length; // cache the length

for ( ; i < len ; i++ ){
    myStringArray[i]; // Don't use this if you plan on changing the length of the array
}

Nowoczesne przeglądarki wszystkie metody iteracyjnej wsparcie forEach, map, reduce, filteri wiele innych sposobów na prototypie Array .

Gabriel
źródło
3
Zauważ, że niektórzy interpretatorzy (np. V8) automatycznie buforują długość tablicy, jeśli kod jest wywoływany wystarczającą liczbę razy i wykrywa, że ​​długość nie jest modyfikowana przez pętlę.
Phrogz
Dzięki za informacje @Phrogz to prawda, że ​​jest wiele optymalizacji, które może wykonać VM, ale ponieważ starsze przeglądarki tego nie mają, najlepszym rozwiązaniem jest optymalizacja, ponieważ jest tak tania.
Gabriel
1
@Gabriel: Dlaczego? Podaj rzeczywiste przykłady pokazujące, że brak buforowania długości jest w rzeczywistości wąskim gardłem wydajności. Postępuję zgodnie z podejściem „przedwczesna optymalizacja jest źródłem wszelkiego zła”. Naprawię tę jedną pętlę, która faktycznie stanowi problem, gdy ją napotkam ...
Stijn de Witt
1
@StijndeWitt imo to tylko kwestia stylistyczna. Szczerze mówiąc, nie używam już nawet pętli, zamiast tego polegam na podkreśleniu dla takich rzeczy jak _.each, _.map itp. Kiedy pisałem takie pętle, buforowałem długość przede wszystkim, aby wszystkie moje deklaracje zmiennych były w jednym miejscu, na górze mojej funkcji. Postępowanie zgodnie z moimi radami w tym zakresie jest nieistotne dla jakiegokolwiek zastosowania w świecie rzeczywistym. Przedwczesna optymalizacja jest bardzo zła, ale jeśli optymalizacja wynika z decyzji stylistycznych, nie sądzę, żeby to miało znaczenie.
Gabriel
1
@Gabriel Wierzę, że JavaScript obsługuje już funkcję mapowania w tablicach, nie trzeba wprowadzać do tego dodatkowej biblioteki.
Noz
28

Istnieje wiele sposobów na przeglądanie tablicy w JavaScript.

Pętla ogólna:

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

ES5's forEach:

substr.forEach(function(item) {
    // Do something with `item`
});

jQuery.each:

jQuery.each(substr, function(index, item) {
    // Do something with `item` (or `this` is also `item` if you like)
});

Spójrz na to, aby uzyskać szczegółowe informacje, możesz też sprawdzić MDN pod kątem zapętlania tablicy w JavaScript i używania jQuery sprawdzania jQuery dla każdego .

RizN81
źródło
27

Poleciłbym całkowicie skorzystać z biblioteki underscore.js . Zapewnia różne funkcje, których można używać do iteracji po tablicach / kolekcjach.

Na przykład:

_.each([1, 2, 3], function(num){ alert(num); });
=> alerts each number in turn...
Andrew Thomson
źródło
7
Dla nowych odkrywców tego pytania chciałbym jedynie zwrócić uwagę na Lo-Dash , duchowego następcę Underscore, który poprawia je na wiele sposobów.
Mark Reed,
3
Po co korzystać, underscorejeśli dodano ECMA-262forEach methor. Kod macierzysty jest zawsze lepszy.
Walter Chapilliquen - wZVanG
27

Pętla tablicowa:

for(var i = 0; i < things.length; i++){
    var thing = things[i];
    console.log(thing);
}

Pętla obiektowa:

for(var prop in obj){
    var propValue = obj[prop];
    console.log(propValue);
}
bzim
źródło
27

Tak , możesz zrobić to samo w JavaScript za pomocą pętli, ale nie jest to ograniczone , istnieje wiele sposobów wykonywania pętli nad tablicami w JavaScript. Wyobraź sobie, że masz tę tablicę poniżej i chcesz zrobić nad nią pętlę:

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

Oto rozwiązania:

1) Dla pętli

forPętla jest powszechnym sposobem zapętlenie poprzez tablice w JavaScript, ale nie traktować jako najszybszych rozwiązań dla dużych tablic:

for (var i=0, l=arr.length; i<l; i++) {
  console.log(arr[i]);
}

2) Podczas pętli

Pętla while jest uważana za najszybszy sposób na przechodzenie przez długie tablice, ale zwykle jest rzadziej używana w kodzie JavaScript:

let i=0;

while (arr.length>i) {
    console.log(arr[i]);
    i++;
}

3) Wykonaj, gdy
A do whilerobi to samo, co whilez pewną różnicą składni, jak poniżej:

let i=0;
do {
  console.log(arr[i]);
  i++;
}
while (arr.length>i);

Są to główne sposoby wykonywania pętli JavaScript, ale jest na to jeszcze kilka sposobów.

Używamy również for inpętli do zapętlania obiektów w JavaScript.

Również spojrzeć na map(), filter(), reduce(), itd funkcji na tablicy w JavaScript. Mogą robić rzeczy znacznie szybciej i lepiej niż przy użyciu whilei for.

To dobry artykuł, jeśli chcesz dowiedzieć się więcej o funkcjach asynchronicznych w tablicach w JavaScript.

Programowanie funkcjonalne cieszy się ostatnio dużym powodzeniem w świecie programistów. I nie bez powodu: techniki funkcjonalne mogą pomóc Ci napisać bardziej deklaratywny kod, który jest łatwiejszy do zrozumienia na pierwszy rzut oka, refaktoryzacji i testu.

Jednym z kamieni węgielnych programowania funkcjonalnego jest specjalne użycie list i operacji na listach. A te rzeczy są dokładnie takie, jakie brzmią: tablice rzeczy i rzeczy, które im robisz. Ale funkcjonalny sposób myślenia traktuje je nieco inaczej niż można się spodziewać.

W tym artykule przyjrzymy się temu, co lubię nazywać operacjami „wielkiej trójki”: mapuj, filtruj i zmniejszaj. Objęcie głowy tymi trzema funkcjami jest ważnym krokiem w kierunku pisania czystego kodu funkcjonalnego i otwiera drzwi do niezwykle potężnych technik programowania funkcjonalnego i reaktywnego.

Oznacza to również, że już nigdy nie będziesz musiał pisać pętli for.

Czytaj więcej >> tutaj :

Alireza
źródło
Czy naprawdę istnieje różnica w wydajności przed pętlą for i chwilą pętli podczas iteracji przez tablicę? Miałem wrażenie, że różnice były przede wszystkim składniowe
shea
24

Jeśli ktoś jest zainteresowany wydajnością wielu mechanizmów dostępnych dla iteracji macierzy, przygotowałem następujące testy JSPerf:

https://jsperf.com/fastest-array-iterator

Wyniki wydajności

Wyniki:

Tradycyjny for()iterator jest zdecydowanie najszybszą metodą, szczególnie gdy jest używany z buforowaną długością tablicy .

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

for(let i=0, size=arr.length; i<size; i++){
    // Do something
}

Metody Array.prototype.forEach()i Array.prototype.map()są najwolniejszymi przybliżeniami, prawdopodobnie w wyniku narzutu wywołania funkcji .

colxi
źródło
lepiej użyć i = i +1zamiasti++
DarckBlezzer
2
Można poprawić: użyj: ++ i zamiast i ++, pozwoli to uniknąć tymczasowego obiektu. Zmniejsza to użycie pamięci i czas procesora (nie wymaga alokacji)!
PowerStat
@ PowerStat czy możesz podać link lub odniesienie do tego? Nigdy o tym nie słyszałem, brzmi interesująco ...
colxi
1
@colxi Aby zobaczyć takie interesujące rzeczy, powinieneś przeczytać hardcorowe teksty C ++ z Herb Sutter i Scott Meyers. Sprawa ++ i vs i ++ pochodzi z książki: Wyjątkowe C ++: 47 zagadek inżynierskich, problemy z programowaniem i rozwiązania - myślę, że można to również znaleźć na gotw.ca, ale można to udowodnić dla każdego języka programowania.
PowerStat
21

Jeśli korzystasz z biblioteki jQuery, rozważ użycie http://api.jquery.com/jQuery.each/

Z dokumentacji:

jQuery.each( collection, callback(indexInArray, valueOfElement) )

Zwraca: Obiekt

Opis: Ogólna funkcja iteratora, której można używać do płynnego iterowania zarówno obiektów, jak i tablic. Tablice i obiekty podobne do tablicy z właściwością length (takie jak obiekt argumentów funkcji) są iterowane przez indeks numeryczny, od 0 do długości-1. Inne obiekty są iterowane według nazwanych właściwości.

$.each()Funkcja jest taka sama jak $(selector).each(), który jest używany do iteracji, wyłącznie za pomocą obiektu jQuery. Tej $.each() funkcji można używać do iteracji w dowolnej kolekcji, niezależnie od tego, czy jest to mapa (obiekt JavaScript), czy tablica. W przypadku tablicy wywołanie zwrotne jest każdorazowo przekazywane do indeksu tablicy i odpowiedniej wartości tablicy. (Do wartości można również uzyskać dostęp za pomocą thissłowa kluczowego, ale JavaScript zawsze zawinie thiswartość jako Objectnawet jeśli jest to zwykły ciąg lub wartość liczbowa.) Metoda zwraca swój pierwszy argument, obiekt, który był iterowany.

justingordon
źródło
9
jQuery na wszystko?
Wyjątek,
6
Zgadzam się z wyjątkiem. Nie lekceważ wpływu dodatkowych zależności. Odradzałbym to, z wyjątkiem kodu, który i tak już intensywnie korzysta z jQuery.
Stijn de Witt
2
Aktualizacja: w dzisiejszych czasach możesz użyć Array.forEach, aby uzyskać ten sam efekt dzięki natywnym tablicom.
Stijn de Witt
20

Nie widziałem jeszcze tej odmiany, która osobiście najbardziej mi się podoba:

Biorąc pod uwagę tablicę:

var someArray = ["some", "example", "array"];

Możesz na nim zapętlić, nie uzyskując dostępu do właściwości length:

for (var i=0, item; item=someArray[i]; i++) {
  // item is "some", then "example", then "array"
  // i is the index of item in the array
  alert("someArray[" + i + "]: " + item);
}

Zobacz ten JsFiddle wykazujący, że: http://jsfiddle.net/prvzk/

Działa to tylko w przypadku tablic, które nie są rzadkie. Oznacza to, że faktycznie każdy indeks w tablicy ma wartość. Odkryłem jednak, że w praktyce rzadko używam rzadkich tablic w JavaScript ... W takich przypadkach zwykle łatwiej jest użyć obiektu jako mapy / tablicy mieszającej. Jeśli masz rzadką tablicę i chcesz zapętlić ponad 0 .. długość-1, potrzebujesz konstrukcji for (var i = 0; i <someArray.length; ++ i), ale nadal potrzebujesz ifwewnętrznej pętli aby sprawdzić, czy element o bieżącym indeksie jest rzeczywiście zdefiniowany.

Ponadto, jak wspomina CMS w komentarzu poniżej, możesz używać tego tylko w tablicach, które nie zawierają żadnych wartości fałszowania. Tablica ciągów z przykładu działa, ale jeśli masz puste ciągi lub liczby, które są 0 lub NaN itp., Pętla przedwcześnie się zerwie. Znowu w praktyce nie jest to dla mnie problemem, ale należy o tym pamiętać, co sprawia, że ​​jest to pętla do przemyślenia przed użyciem ... To może zdyskwalifikować niektóre osoby :)

W tej pętli podoba mi się:

  • Krótko pisać
  • Nie trzeba uzyskiwać dostępu (nie mówiąc już o buforowaniu) do właściwości length
  • Dostęp do elementu jest automatycznie definiowany w treści pętli pod wybraną nazwą.
  • Łączy się bardzo naturalnie z array.push i array.splice, aby używać tablic takich jak listy / stosy

Powodem tego jest to, że specyfikacja tablicy nakazuje, aby po odczytaniu elementu z indeksu> = długość tablicy zwrócił niezdefiniowany. Gdy napiszesz w takiej lokalizacji, faktycznie zaktualizuje długość.

Dla mnie ten konstrukt najbardziej naśladuje składnię Java 5, którą kocham:

for (String item : someArray) {
}

... z dodatkową korzyścią wynikającą z wiedzy o bieżącym indeksie wewnątrz pętli

Stijn de Witt
źródło
13
Zauważmy, że z takim podejściem pętla będzie zatrzymać tak szybko znajdzie wartość falsey , takich jak pusty ciąg, 0, false, NaN, nulllub undefined, jeszcze zanim iosiągnie długość, np jsfiddle.net/prvzk/1
CMS
3
Warunkiem pętli może być (item=someArray[i]) !== undefined.
daniel1426
18

Istnieje metoda iteracji tylko nad własnymi właściwościami obiektu, nie obejmującymi właściwości prototypu:

for (var i in array) if (array.hasOwnProperty(i)) {
    // Do something with array[i]
}

ale nadal będzie iterować po niestandardowych właściwościach.

W JavaScript każda własność niestandardowa może być przypisana do dowolnego obiektu, w tym tablicy.

Jeśli ktoś chce iteracyjne nad sparsed tablicy, for (var i = 0; i < array.length; i++) if (i in array)lub array.forEachze es5shimpowinien być stosowany.

kirilloid
źródło
A co powiesz na używanie for (var i in array) if (++i)?
Daniel Sokołowski
15

Jest kilka sposobów na zrobienie tego w JavaScript. Pierwsze dwa przykłady to próbki JavaScript. Trzecia wykorzystuje bibliotekę JavaScript, czyli jQuery korzystającą z tej .each()funkcji.

var myStringArray = ["hello", "World"];
for(var i in myStringArray) {
  alert(myStringArray[i]);
}

var myStringArray = ["hello", "World"];
for (var i=0; i < myStringArray.length; i++) {
  alert(myStringArray[i]);
}

var myStringArray = ["hello", "World"];
$.each(myStringArray, function(index, value){
  alert(value);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Shubham Khatri
źródło
for...innależy unikać obiektów podobnych do tablicy
brk
15

Najbardziej elegancki i szybki sposób

var arr = [1, 2, 3, 1023, 1024];
for (var value; value = arr.pop();) {
    value + 1
}

http://jsperf.com/native-loop-performance/8


Edytowane (ponieważ się myliłem)


Porównywanie metod zapętlania tablicy 100 000 elementów i za każdym razem wykonuj minimalną operację z nową wartością.

Przygotowanie:

<script src="//code.jquery.com/jquery-2.1.0.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
<script>
    Benchmark.prototype.setup = function() {
        // Fake function with minimal action on the value
        var tmp = 0;
        var process = function(value) {
            tmp = value; // Hold a reference to the variable (prevent engine optimisation?)
        };

        // Declare the test Array
        var arr = [];
        for (var i = 0; i < 100000; i++)
            arr[i] = i;
    };
</script>

Testy:

<a href="http://jsperf.com/native-loop-performance/16" 
   title="http://jsperf.com/native-loop-performance/16"
><img src="http://i.imgur.com/YTrO68E.png" title="Hosted by imgur.com" /></a>
molokoloco
źródło
Ta pętla nie wydaje się być zgodna z kolejnością elementów w tablicy.
Deniz Ozger
Mój test był zły. Jest poprawne, pokazuje teraz wszystkie LOOPS. jsperf.com/native-loop-performance/16
molokoloco
@bergi ma rację. Ta pętla usuwa tablicę podczas jej zapętlania. W większości przypadków nie to, czego chcesz.
Stijn de Witt
4
psuje się na przedmiotach falsey.
njzk2
12

Zoptymalizowane podejście polega na buforowaniu długości tablicy i użyciu wzorca pojedynczego var inicjującego wszystkie zmienne jednym słowem kluczowym var.

var i, max, myStringArray = ["Hello","World"];
for (i = 0, max = myStringArray.length; i < max; i++) {
    alert(myStringArray[i]);
   //Do something
}

Jeśli kolejność iteracji nie ma znaczenia, powinieneś wypróbować odwróconą pętlę, jest to najszybsze, ponieważ zmniejsza testowanie warunków ogólnych i dekrementacja jest w jednym wyrażeniu:

var i,myStringArray = ["item1","item2"];
for (i =  myStringArray.length; i--) {
    alert(myStringArray[i]);
}

lub lepszy i czystszy w użyciu podczas pętli while:

var myStringArray = ["item1","item2"],i = myStringArray.length;
while(i--) {
   // do something with fruits[i]
}
Zaheer Ahmed
źródło
12

W JavaScript jest tak wiele rozwiązań do zapętlania tablicy.

Poniższy kod jest popularny

/** Declare inputs */
const items = ['Hello', 'World']

/** Solution 1. Simple for */
console.log('solution 1. simple for')

for (let i = 0; i < items.length; i++) {
  console.log(items[i])
}

console.log()
console.log()

/** Solution 2. Simple while */
console.log('solution 2. simple while')

let i = 0
while (i < items.length) {
  console.log(items[i++])
}

console.log()
console.log()

/** Solution 3. forEach*/
console.log('solution 3. forEach')

items.forEach(item => {
  console.log(item)
})

console.log()
console.log()

/** Solution 4. for-of*/
console.log('solution 4. for-of')

for (const item of items) {
  console.log(item)
}

console.log()
console.log()

Alongkorn Chetasumon
źródło
12

Jeśli chcesz użyć jQuery, ma ładny przykład w swojej dokumentacji:

 $.each([ 52, 97 ], function( index, value ) {
      alert( index + ": " + value );
 });
jj_
źródło
12

Moim zdaniem najlepszym sposobem jest użycie funkcji Array.forEach. Jeśli nie możesz tego użyć, sugerowałbym, abyś otrzymał polifill z MDN. Aby był dostępny, jest to z pewnością najbezpieczniejszy sposób na iterację tablicy w JavaScript.

Array.prototype.forEach ()

Tak jak sugerowali inni, prawie zawsze tego chcesz:

var numbers = [1,11,22,33,44,55,66,77,88,99,111];
var sum = 0;
numbers.forEach(function(n){
  sum += n;
});

Zapewnia to, że wszystko, czego potrzebujesz w zakresie przetwarzania tablicy, pozostanie w tym zakresie i że przetwarzasz tylko wartości tablicy, a nie właściwości obiektu i innych elementów, co się for ..dzieje.

Używając zwykłego stylu C. for pętli w działa w większości przypadków. Należy tylko pamiętać, że wszystko w pętli ma ten sam zakres co reszta programu, {} nie tworzy nowego zakresu.

W związku z tym:

var sum = 0;
var numbers = [1,11,22,33,44,55,66,77,88,99,111];

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

alert(i);

wyświetli „11” - co może, ale nie musi być tym, czego chcesz.

Działający przykład jsFiddle: https://jsfiddle.net/workingClassHacker/pxpv2dh5/7/

Espen
źródło
10

Nie jest w 100% identyczny, ale podobny:

   var myStringArray = ['Hello', 'World']; // array uses [] not {}
    for (var i in myStringArray) {
        console.log(i + ' -> ' + myStringArray[i]); // i is the index/key, not the item
    }

Muhammad Alvin
źródło
1
Wydaje się, że napotkałoby to na podobne problemy, jak inne w zastosowaniach z obiektem tablicowym, w tym prototypowe zmienne składowe również byłyby wychwytywane przez for in.
Kzqai
9

Na przykład użyłem w konsoli Firefox:

[].forEach.call(document.getElementsByTagName('pre'), function(e){ 
   console.log(e);
})
victorq10
źródło
9
var x = [4, 5, 6];
for (i = 0, j = x[i]; i < x.length; j = x[++i]) {
    console.log(i,j);
}

Dużo czystsze ...

staticd
źródło
To nie jest bardzo czyste w porównaniu do z.forEach(j => console.log(j));.
Sapphire_Brick
9

Krótka odpowiedź: tak. Możesz to zrobić:

var myArray = ["element1", "element2", "element3", "element4"];

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

W konsoli przeglądarki można wydrukować coś takiego jak „element1”, „element2” itp.

Juanjo Salvador
źródło
9

Możesz użyć Array.prototype.forEach(...):

var arr = ["apple", "banana", "cherry", "mango"];
arr.forEach((item, index)=>{
   //Some code...
});

Lub Array.prototype.map(...):

var arr = ["apple", "banana", "cherry", "mango"];
arr.map((item, index)=>{
   //Some code...
});

Lub jquery lub wcześniej wspomniane sposoby pętli.

Sapphire_Brick
źródło