For-each over an array in JavaScript
Jak mogę zapętlić wszystkie wpisy w tablicy używając JavaScript?
Myślałem, że to coś takiego:
forEach(instance in theArray)
Gdzie theArray
jest moją tablicą, ale wydaje się to być błędne.
30 answers
TL; DR
-
Twoje najlepsze zakłady to zazwyczaj
-
Nie używaj
for-in
chyba że używasz go z zabezpieczeniami lub są przynajmniej świadomi, dlaczego może cię ugryźć. -
Nie używaj
map
(spec
|MDN
) jeśli nie używasz zwracanej wartościmap
.
(niestety ktoś tam uczymap
jakby to byłoforEach
-map
's zadanie polega na utworzeniu nowej tablicy z wartości oryginalnej przekazanej przez funkcję mapowania, nie używaj jej tylko do iteracji)
Ale jest wiele więcej do odkrycia, Czytaj dalej...
JavaScript ma potężną semantykę do zapętlania tablic i obiektów podobnych do tablic. Podzieliłem odpowiedź na dwie części: opcje dla oryginalnych tablic i opcje dla rzeczy, które są tylko tablicami - , takich jak, takie jak obiekt arguments
, Inne iterable objects (ES2015+), Kolekcje DOM i tak dalej.
Szybko zauważ, że możesz używać opcji ES2015 teraz , nawet na silnikach ES5, przez transpiling ES2015 do ES5. Szukaj "ES2015 transpiling" / "ES6 transpiling", aby uzyskać więcej informacji...
Dobra, spójrzmy na nasze opcje:
Dla Rzeczywistych Tablic
Masz trzy opcje w ECMAScript 5 ("ES5"), wersji najbardziej obecnie obsługiwanej, i dwie dodatkowe dodane w ECMAScript 2015 ("ES2015", "ES6"):
- użycie
forEach
i pokrewne (ES5+) - użyj prostej
for
pętli - użycie
for-in
poprawnie
Nie jest to jednak możliwe, ponieważ nie jest to możliwe.]}
W tym celu należy użyć iteratora w sposób jawny (ES2015+).]}
Szczegóły:
1. Użycie forEach
i pokrewne
W dowolnym nowoczesnym środowisku (a więc nie IE8), gdzie masz dostęp do Array
funkcji dodanych przez ES5 (bezpośrednio lub za pomocą polyfills), możesz użyć forEach
(spec
| MDN
):
var a = ["a", "b", "c"];
a.forEach(function(entry) {
console.log(entry);
});
forEach
akceptuje oddzwanianie funkcja i, opcjonalnie, wartość do użycia jako this
podczas wywoływania tego wywołania zwrotnego (nie używana powyżej). Wywołanie zwrotne jest wywoływane dla każdego wpisu w tablicy, w kolejności, pomijając nieistniejące wpisy w rzadkich tablicach. Chociaż użyłem tylko jednego argumentu powyżej, wywołanie zwrotne jest wywoływane z trzema: wartością każdego wpisu, indeksem tego wpisu i odniesieniem do tablicy, którą iterujesz (na wypadek, gdyby twoja funkcja nie miała go pod ręką).
Chyba że obsługujesz przestarzałe przeglądarki podobnie jak IE8 (który netapps wykazuje nieco ponad 4% udziału w rynku od tego napisania we wrześniu 2016), możesz szczęśliwie używać forEach
na stronie ogólnego przeznaczenia bez podkładki. Jeśli potrzebujesz obsługiwać przestarzałe przeglądarki, shimming/polyfilling forEach
jest łatwo zrobić (wyszukaj "ES5 shim" dla kilku opcji).
forEach
ma tę zaletę, że nie musisz deklarować zmiennych indeksujących i wartości w zakresie zawierającym, ponieważ są one dostarczane jako argumenty funkcji iteracji, a więc ładnie dopasowane do tej iteracji.
Jeśli martwisz się o koszt wywołania funkcji dla każdego wpisu tablicy, nie bądź; details.
Dodatkowo, forEach
jest funkcją "loop through them all", ale ES5 zdefiniował kilka innych przydatnych funkcji "work your way through the array and do things", w tym:
-
every
(zatrzymuje zapętlanie przy pierwszym zwrocie wywołania zwrotnegofalse
lub coś w tym stylu falsey) -
some
(zatrzymuje zapętlanie przy pierwszym zwrocie wywołania zwrotnegotrue
lub coś prawdziwego) -
filter
(tworzy nową tablicę zawierającą elementy, w których funkcja filtra zwracatrue
i pomija te, w których zwracafalse
) -
map
(tworzy nową tablicę z wartości zwracanych przez wywołanie zwrotne) -
reduce
(buduje wartość przez wielokrotne wywołanie wywołania zwrotnego, przechodząc w poprzednim wartości; szczegóły można znaleźć w specyfikacji; przydatne do sumowania zawartości tablicy i wielu innych rzeczy) -
reduceRight
(podobnie jakreduce
, ale działa w porządku malejącym, a nie rosnącym) [158]}
2. Użyj prostej pętli for
Czasami stare sposoby są najlepsze:
var index;
var a = ["a", "b", "c"];
for (index = 0; index < a.length; ++index) {
console.log(a[index]);
}
Jeśli długość tablicy nie zmieni się podczas pętli, a jest w kodzie wrażliwym na wydajność (mało prawdopodobne), nieco bardziej skomplikowana wersja chwytając długość z przodu może być tiny trochę szybciej:
var index, len;
var a = ["a", "b", "c"];
for (index = 0, len = a.length; index < len; ++index) {
console.log(a[index]);
}
I/lub liczenie wstecz:
var index;
var a = ["a", "b", "c"];
for (index = a.length - 1; index >= 0; --index) {
console.log(a[index]);
}
Ale z nowoczesnymi silnikami JavaScript, rzadko trzeba wycisnąć ten ostatni kawałek soku.
W ES2015 i nowszych możesz ustawić zmienne indeks i wartość lokalnie w pętlifor
:
let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
let value = a[index];
console.log(index, value);
}
//console.log(index); // would cause "ReferenceError: index is not defined"
//console.log(value); // would cause "ReferenceError: value is not defined"
let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
let value = a[index];
console.log(index, value);
}
try {
console.log(index);
} catch (e) {
console.error(e); // "ReferenceError: index is not defined"
}
try {
console.log(value);
} catch (e) {
console.error(e); // "ReferenceError: value is not defined"
}
I kiedy to robisz, nie tylko value
ale także W przypadku pętli, w której nie ma żadnej pętli, nie jest to możliwe, ponieważ w pętli tej nie ma żadnej pętli, a w pętli tej nie ma żadnej pętli.]}
let divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
divs[index].addEventListener('click', e => {
console.log("Index is: " + index);
});
}
let divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
divs[index].addEventListener('click', e => {
console.log("Index is: " + index);
});
}
<div>zero</div>
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>
Jeśli masz pięć div, dostaniesz "Index is: 0", jeśli klikniesz pierwszy i "Index is: 4", Jeśli klikniesz ostatni. To działa nie jeśli używasz var
zamiast let
.
3. Użycie for-in
poprawnie
Dostaniesz ludzi kazanie Ci używać for-in
, ale to nie jest to, co for-in
jest dla. for-in
pętli przez wylicz właściwości obiektu , a nie indeksy tablicy. kolejność nie jest gwarantowana , nawet w ES2015 (ES6). ES2015 + definiuje kolejność właściwości obiektu (poprzez [[OwnPropertyKeys]]
, [[Enumerate]]
, i rzeczy, które ich używają jak Object.getOwnPropertyKeys
), ale nie zdefiniowano, że for-in
będzie postępować zgodnie z tą kolejnością; jednak ES2020 to zrobił. (Szczegóły w ta druga odpowiedź.)
Jedynymi prawdziwymi przypadkami użyciafor-in
na tablicy są:
- to sparse tablice z masywne luki w nim, lub
- używasz właściwości nieelementowych i chcesz umieścić je w pętli
Patrząc tylko na pierwszy przykład: możesz użyć for-in
, aby odwiedzić te rzadkie elementy tablicy, jeśli użyjesz odpowiednich zabezpieczenia:
// `a` is a sparse array
var key;
var a = [];
a[0] = "a";
a[10] = "b";
a[10000] = "c";
for (key in a) {
if (a.hasOwnProperty(key) && // These checks are
/^0$|^[1-9]\d*$/.test(key) && // explained
key <= 4294967294 // below
) {
console.log(a[key]);
}
}
Zwróć uwagę na trzy kontrole:
-
Że obiekt posiada swoją własność własną o tej nazwie (nie taką, którą dziedziczy po swoim prototypie), oraz
-
Że kluczem są wszystkie cyfry dziesiętne (np. normalna forma ciągu, a nie notacja naukowa) oraz
-
Że wartość klucza przy wymuszeniu do liczby wynosi w specyfikacji . Pozostałe liczby (liczby niezliczone, liczby ujemne, liczby większe niż 2^32 - 2) nie są indeksami tablicowymi. Powodem jest 2^32 - 2 czy to sprawia, że największa wartość indeksu jest niższa niż 2^32 - 1, jest to maksymalna wartość, jaką może mieć tablica
length
. (Np. długość tablicy mieści się w 32-bitowej niepodpisanej liczbie całkowitej.) (rekwizyty dla Robga za wskazanie w komentarzu na moim blogu że mój poprzedni test nie był całkiem dobry.)
Nie zrobiłbyś tego w kodzie inline, oczywiście. Napisałbyś funkcję użytkową. Być może:
// Utility function for antiquated environments without `forEach`
var hasOwn = Object.prototype.hasOwnProperty;
var rexNum = /^0$|^[1-9]\d*$/;
function sparseEach(array, callback, thisArg) {
var index;
for (var key in array) {
index = +key;
if (hasOwn.call(a, key) &&
rexNum.test(key) &&
index <= 4294967294
) {
callback.call(thisArg, array[key], index, array);
}
}
}
var a = [];
a[5] = "five";
a[10] = "ten";
a[100000] = "one hundred thousand";
a.b = "bee";
sparseEach(a, function(value, index) {
console.log("Value at " + index + " is " + value);
});
4. W tym celu należy użyć iteratora.]}
ES2015 dodał Iteratory do JavaScript. Najprostszym sposobem użycia iteratorów jest nowa Instrukcja for-of
. Wygląda to tak:
const a = ["a", "b", "c"];
for (const val of a) {
console.log(val);
}
Pod kołdrą, że pobiera iterator z tablicy i pętli przez nią, pobierając z niej wartości. Nie ma problemu, jaki ma użycie for-in
, ponieważ używa iteratora zdefiniowanego przez obiekt (tablicę), a tablice definiują, że ich Iteratory są iteracyjne poprzez ich wpisy (Nie ich właściwości). W przeciwieństwie do for-in
W ES5, kolejność odwiedzania wpisów jest kolejnością liczbową ich indeksów.
5. Jawnie używaj iteratora (ES2015+)
Czasami warto użyć iteratora jawnie . To też możesz zrobić, chociaż jest o wiele bardziej clunkierne niż for-of
. Wygląda to tak:
const a = ["a", "b", "c"];
const it = a.values();
let entry;
while (!(entry = it.next()).done) {
console.log(entry.value);
}
Iterator jest obiektem pasującym do definicji iteratora w specyfikacji. Jej metoda next
zwraca nowy obiekt wynikowy za każdym razem, gdy go wywołasz. Obiekt wynikowy ma właściwość done
, informującą o tym, czy został wykonany, oraz właściwość value
z wartością dla tej iteracji. (done
jest opcjonalne, jeśli byłoby false
, value
jest opcjonalne, jeśli byłoby undefined
.)
Jest różne; tablice obsługują (przynajmniej) trzy funkcje zwracające Iteratory:
-
values()
: to jest ten, którego użyłem powyżej. Zwraca iterator, gdzie każdyvalue
jest wpisem tablicy dla tej iteracji ("a"
,"b"
, i"c"
w przykładzie wcześniejszym). -
keys()
: zwraca iterator, w którym każdyvalue
jest kluczem do tej iteracji(więc dla naszegoa
powyżej, to będzie"0"
, następnie"1"
, następnie"2"
). -
entries()
: zwraca iterator, gdzie każdyvalue
jest tablicą w postaci[key, value]
dla tej iteracji.
Dla Obiektów Podobnych Do Tablicy
Oprócz prawdziwych tablic, istnieją również podobne do tablicy obiekty, które mają właściwość length
oraz właściwości o nazwach numerycznych: NodeList
instancje, obiekt arguments
, itd. Jak pętli przez ich zawartość?
Użyj dowolnej z powyższych opcji dla tablic
[146]}przynajmniej niektóre, a być może Większość lub nawet wszystkie powyższe podejścia do tablicy często stosują się równie dobrze do obiektów podobnych do tablicy: [149]}-
Use
forEach
and related (ES5+)Różne funkcje na
Array.prototype
są "celowo ogólne" i mogą być zwykle używane na obiektach podobnych do tablicy poprzezFunction#call
lubFunction#apply
. (Zobacz zastrzeżenie dla obiekt dostarczony przez hosta na końcu tej odpowiedzi, ale jest to rzadki problem.)Załóżmy, że chcesz użyć
forEach
naNode
'SchildNodes
właściwość. Zrobiłbyś to:Array.prototype.forEach.call(node.childNodes, function(child) { // Do something with `child` });
Jeśli zamierzasz robić to często, możesz chcieć pobrać kopię referencji funkcji do zmiennej w celu ponownego użycia, np.:
// (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` });
-
Użyj prostej pętli
for
Oczywiście, prosta
for
pętla ma zastosowanie do tablicy obiektów. -
Użycie
for-in
prawidłowofor-in
z tymi samymi zabezpieczeniami jak w przypadku tablicy powinny działać również z obiektami podobnymi do tablicy; może mieć zastosowanie zastrzeżenie dla obiektów dostarczanych przez host na #1 powyżej. -
Use
for-of
(use an iterator implicite) (ES2015+)for-of
używa iteratora dostarczonego przez obiekt (jeśli istnieje). Obejmuje to obiekty dostarczone przez hosta. Na przykład SpecyfikacjaNodeList
z {[126] } została zaktualizowana, aby wspierać iterację. Spec dlaHTMLCollection
zgetElementsByTagName
nie było. -
Jawnie używaj iteratora (ES2015+)
Zobacz #4.
Utwórz prawdziwą tablicę
Innym razem możesz chcieć przekonwertować obiekt podobny do tablicy na tablicę rzeczywistą. Jest to zaskakująco łatwe:
-
Użyj metody
slice
tablicMożemy użyj
slice
metoda tablic, która podobnie jak inne metody wymienione powyżej jest "celowo ogólna" i dlatego może być używana z obiektami typu tablica, jak poniżej:var trueArray = Array.prototype.slice.call(arrayLikeObject);
Więc na przykład, jeśli chcemy przekonwertować
NodeList
do tablicy prawdziwej, możemy to zrobić:var divs = Array.prototype.slice.call(document.querySelectorAll("div"));
Zobacz Zastrzeżenie dla obiektów dostarczanych przez host poniżej. W szczególności, zauważ, że to nie powiedzie się w IE8 i wcześniejszych, które nie pozwalają używać obiektów dostarczanych przez host jako
this
jak to. -
Użyj składni spread (
...
)Możliwe jest również użycie składni rozproszonej ES2015 z silnikami JavaScript, które obsługują tę funkcję. Podobnie jak
for-of
, używa iteratora dostarczonego przez obiekt (patrz #4 w poprzedniej sekcji):var trueArray = [...iterableObject];
Na przykład, jeśli chcemy przekonwertować
NodeList
do prawdziwej tablicy, ze składnią spread staje się to dość zwięzłe:var divs = [...document.querySelectorAll("div")];
-
Użycie
Array.from
Array.from
(spec) | (MDN) (ES2015+, ale łatwo polyfilled) tworzy tablicę z obiektu podobnego do tablicy, opcjonalnie przekazując wpisy jako pierwsze przez funkcję mapowania. Więc:var divs = Array.from(document.querySelectorAll("div"));
Lub jeśli chcesz uzyskać tablicę nazw znaczników elementów z podaną klasą, użyj funkcji mapowania:
// 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; });
Zastrzeżenie dla obiektów dostarczanych przez hosta
Jeśli używasz Array.prototype
funkcji z host-provided array-like objects( listy DOM i inne rzeczy dostarczane przez przeglądarkę, a nie silnik JavaScript), musisz upewnić się, że testujesz w swoich środowiskach docelowych, aby upewnić się, że obiekt host-provided zachowuje się poprawnie. Większość zachowuje się prawidłowo (teraz), ale ważne jest, aby przetestować. Powodem jest to, że większość metod Array.prototype
, których prawdopodobnie chcesz użyć, opiera się na obiekcie dostarczonym przez hosta, dając szczerą odpowiedź na streszczenie [[HasProperty]]
operacja. W momencie pisania tego tekstu przeglądarki wykonują bardzo dobrą robotę, ale specyfikacja 5.1 pozwoliła na to, że obiekt dostarczany przez host może nie być uczciwy. Jest w §8.6.2, kilka akapitów pod dużą tabelą na początku tej sekcji), Gdzie jest napisane:
Obiekty hosta mogą zaimplementować te wewnętrzne metody w dowolny sposób, chyba że określono inaczej; na przykład, jedną z możliwości jest to, że
[[Get]]
i[[Put]]
dla konkretnego obiektu hosta rzeczywiście pobierają i przechowuje wartości właściwości, ale[[HasProperty]]
zawsze generuje false.
(nie mogłem znaleźć równoważnej wersji w specyfikacji ES2015, ale na pewno nadal tak jest.) Ponownie, w momencie pisania tego typu obiektów w nowoczesnych przeglądarkach [NodeList
instancje, na przykład] robią obsługują [[HasProperty]]
poprawnie, ale ważne jest, aby przetestować.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-09 16:04:50
Uwaga : ta odpowiedź jest beznadziejnie nieaktualna. Aby uzyskać bardziej nowoczesne podejście, spójrz na metody dostępne w tablicy . Metody zainteresowań mogą być:
- forEach
- Mapa
- filtr
- zip
- reduce
- każdy
- niektóre
Standardowy sposób iteracji tablicy w JavaScript to vanilla for
- loop:
var length = arr.length,
element = null;
for (var i = 0; i < length; i++) {
element = arr[i];
// Do something with element
}
Należy jednak pamiętać, że takie podejście jest dobre tylko wtedy, gdy masz gęsta tablica, a każdy indeks jest zajęty przez element. Jeśli tablica jest rzadka, to możesz napotkać problemy z wydajnością z tym podejściem, ponieważ będziesz iteracją wielu indeksów, które nie istnieją naprawdę w tablicy. W tym przypadku pętla for .. in
może być lepszym pomysłem. jednakże , musisz użyć odpowiednich zabezpieczeń, aby upewnić się, że działają tylko pożądane właściwości tablicy (tzn. elementy tablicy), ponieważ pętla for..in
- będzie również wyliczona w starsze przeglądarki, lub jeśli dodatkowe właściwości są zdefiniowane jako enumerable
.
W ECMAScript 5 w prototypie tablicy znajdzie się metoda forEach, ale nie jest ona obsługiwana w starszych przeglądarkach. Aby móc używać go konsekwentnie, musisz mieć środowisko, które go wspiera (na przykład Node.js dla JavaScript po stronie serwera), lub użyć "Polyfill". Polyfill dla tej funkcjonalności jest jednak banalny, a ponieważ sprawia, że kod jest łatwiejszy do odczytania, jest to dobry polyfill to include.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-03 19:57:21
Jeśli używasz jQuery biblioteki, możesz użyć jQuery.każdy:
$.each(yourArray, function(index, value) {
// do your stuff here
});
EDIT:
Jak na pytanie, użytkownik chce kod w javascript zamiast jquery więc edycja jest
var length = yourArray.length;
for (var i = 0; i < length; i++) {
// Do something with yourArray[i].
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-12 05:17:40
Pętla do tyłu
Myślę, że odwrotność dla pętli zasługuje na wzmiankę tutaj:
for (var i = array.length; i--; ) {
// process array[i]
}
Zalety:
- nie musisz deklarować tymczasowej zmiennej
len
ani porównywać zarray.length
przy każdej iteracji, z których każda może być minutową optymalizacją. - usuwanie rodzeństwa Z DOM w odwrotnej kolejności jest zwykle bardziej efektywne . (Przeglądarka musi mniej przesuwać elementy w swojej wewnętrznej tablice.)
- jeśli zmodyfikujesz tablicę podczas zapętlania, przy indeksie i lub po nim (na przykład usuniesz lub wstawisz element w
array[i]
), wtedy pętla do przodu pominie element, który został przesunięty w lewo na pozycję i , lub ponownie przetworzy i {54]} ten element, który został przesunięty w prawo. W tradycyjnej pętli for można zaktualizować i , aby wskazać następny element, który wymaga przetworzenia - 1, ale po prostu odwrócenie kierunku iteracji jest często prostsze i bardziej eleganckie rozwiązanie . - podobnie, podczas modyfikowania lub usuwania zagnieżdżonych elementów DOM, przetwarzanie w odwrotnej kolejności może obejść błędy . Na przykład rozważ modyfikację innerHTML węzła nadrzędnego przed obsługą jego dzieci. Do czasu osiągnięcia węzła potomnego zostanie on odłączony od DOM, po zastąpieniu go nowo utworzonym węzłem potomnym, gdy rodzic został napisany innerHTML.
- jest krótszy aby wpisać, i Czytaj , niż niektóre z innych dostępnych opcji. Chociaż przegrywa z
forEach()
i zfor ... of
ES6.
Wady:
- przetwarza elementy w odwrotnej kolejności. Jeśli budujesz nową tablicę z wyników lub drukujesz rzeczy na ekranie, naturalnie wynik zostanie odwrócony w stosunku do pierwotnej kolejności.
- wielokrotne wstawianie rodzeństwa do domu jako pierwszego dziecka w celu zachowania porządku jest mniej efektywny . (Przeglądarka musiałaby ciągle przesuwać rzeczy w prawo.) Aby tworzyć węzły DOM sprawnie i w porządku, wystarczy zapętlić do przodu i dołączyć jak zwykle (a także użyć "fragmentu dokumentu").
- odwrotna pętla jest myląca dla młodszych programistów. (Można uznać, że zaletą, w zależności od perspektywy.)
Czy zawsze powinienem go używać?
Niektórzy programiści używają odwrotnej pętli domyślnie, chyba że istnieje dobry powód pętla do przodu.
Chociaż wzrost wydajności jest zwykle nieznaczny, to w pewnym sensie krzyczy:]}"po prostu zrób to do każdego elementu na liście, nie obchodzi mnie kolejność!"
Jednak w praktyce jest to Nie w rzeczywistości wiarygodne wskazanie intencji, ponieważ jest to nieodróżnialne od tych przypadków, gdy do dbać o porządek i naprawdę zrobić potrzeba zapętlić w odwrotnej kolejności. Więc faktycznie potrzebny byłby inny konstrukt, aby dokładnie wyrazić intencję" don 't care", coś obecnie niedostępnego w większości języków, w tym ECMAScript, ale który można by nazwać na przykład forEachUnordered()
.
Jeśli kolejność nie ma znaczenia, a wydajność jest problemem (w najbardziej wewnętrznej pętli silnika gry lub animacji), to może być dopuszczalne użycie pętli odwrotnej Dla jako wzorca. Pamiętaj tylko, że zobaczenie pętli odwrotnej dla w istniejącym kodzie Nie musi oznaczać , że kolejność nieistotna!
Lepiej było użyć forEach ()
Ogólnie dla kodu wyższego poziomu, gdzie przejrzystość i bezpieczeństwo są większe obawy, wcześniej zalecałem użycie Array::forEach
jako domyślny wzorzec pętli (chociaż obecnie wolę używać for..of
). W przeciwieństwie do pętli odwrotnej, pętla odwrotna nie jest pętlą odwrotną.]}
- to jest bardziej czytelne.
- oznacza to, że i nie zostanie przesunięty wewnątrz bloku (co jest zawsze możliwą niespodzianką ukrywającą się w długich pętlach
for
iwhile
). - daje Ci swobodę zamykania.
- zmniejsza wyciek zmiennych lokalnych i przypadkowe kolizje z (i mutacji) zmiennych zewnętrznych.
Wtedy, gdy widzisz pętlę odwrotną dla kodu, jest to wskazówka, że jest ona odwrócona z ważnego powodu (być może z jednego z powodów opisanych powyżej). A widzenie tradycyjnej pętli for For może wskazywać, że zmiana może mieć miejsce.
(jeśli dyskusja na temat intencji nie ma dla Ciebie sensu, wtedy ty i twój kod możecie skorzystać z wykładu Crockforda na temat programowania Style & Your Brain .)
Jest teraz jeszcze lepiej używać dla..of!
Toczy się dyskusja o tym, czy for..of
czy forEach()
są lepsze:
Dla maksymalnej obsługi przeglądarki,
for..of
wymaga polyfill dla iteratorów, co sprawia, że aplikacja jest nieco wolniejsza i nieco większy do pobrania.Z tego powodu (i zachęcić do korzystania z
map
ifilter
), niektóre front-end style guides banfor..of
całkowicie!Powyższe obawy nie dotyczą jednak Node.aplikacje js, gdzie
for..of
jest teraz dobrze obsługiwane.A ponadto
await
nie działa wewnątrzforEach()
. Użyciefor..of
jest najczystszym wzorem w tym przypadku.
Osobiście, Ja mają tendencję do używania tego, co wygląda najłatwiej przeczytać, chyba że wydajność lub minifikacja stała się głównym problemem. Więc w dzisiejszych czasach wolę używać for..of
zamiast forEach()
, ale zawsze będę używać map
lub filter
lub find
lub some
w stosownych przypadkach.
(Ze względu na kolegów rzadko używam reduce
.)
Jak to działa?
for (var i = 0; i < array.length; i++) { ... } // Forwards
for (var i = array.length; i--; ) { ... } // Reverse
Zauważysz, że i--
jest klauzulą środkową (gdzie zwykle widzimy porównanie) i ostatnią klauzulą jest pusty (gdzie zwykle widzimy i++
). Oznacza to, że i--
jest również używany jako warunek dla kontynuacji. Co najważniejsze, jest ona wykonywana i sprawdzana przed każdą iteracją.
-
Jak może zacząć się od
array.length
bez eksplodowania?Ponieważ
i--
uruchamia przed każdą iteracją, na pierwszej iteracji będziemy mieli dostęp do elementu warray.length - 1
, który unika wszelkich problemów zArray-out-of-boundsundefined
pozycji. -
Dlaczego nie przestaje iteracji przed indeksem 0?
Pętla zatrzyma iterację, gdy warunek
i--
obliczy wartość FALSE ' a (gdy Da 0).Sztuczka polega na tym, że w przeciwieństwie do
--i
, Operator końcowyi--
zmniejszai
, ale daje wartość przed dekret. Twoja konsola może to zademonstrować:> var i = 5; [i, i--, i];
[5, 5, 4]
Więc na ostatecznej iteracji, i był wcześniej 1 i wyrażenie
i--
zmienia je na 0 ale faktycznie daje 1 (truthy), a więc warunek mija. W następnej iteracjii--
zmienia i na -1 ale plony 0 (false), powodując natychmiastowe opuszczenie dolnej części pętli.W tradycyjnym forward for loop,
i++
i++i
są wymienne (jak wskazuje Douglas Crockford). Jednak w odwrotnej pętli for, ponieważ nasz dekrement jest również naszym wyrażeniem warunkowym, musimy trzymać sięi--
jeśli chcemy przetworzyć element w indeksie 0.
Ciekawostki
Niektórzy ludzie lubią narysować małą strzałkę na odwrocie for
pętlę i zakończyć mrugnięciem oka:
for (var i = array.length; i --> 0 ;) {
/ align = "center" bgcolor = "# e0ffe0 " / cesarz chin / / align = center /
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-20 04:11:06
Niektóre języki C używają foreach
do pętli przez wyliczenia. W JavaScript odbywa się to za pomocą for..in
Struktura pętli :
var index,
value;
for (index in obj) {
value = obj[index];
}
Jest pewien haczyk. for..in
będzie przeszukiwać każdy z elementów obiektu oraz elementy znajdujące się na jego prototypie. Aby uniknąć odczytu wartości dziedziczonych przez prototyp obiektu, po prostu sprawdź, czy właściwość należy do obiektu:
for (i in obj) {
if (obj.hasOwnProperty(i)) {
//do stuff
}
}
Dodatkowo, ECMAScript 5 dodał forEach
metoda Array.prototype
, która może być użyta do wyliczenia tablicy za pomocą kalbacka (polyfill jest w dokumentach, więc nadal możesz go używać w starszych przeglądarkach):
arr.forEach(function (val, index, theArray) {
//do stuff
});
Ważne jest, aby pamiętać, że Array.prototype.forEach
nie pęka, gdy callback zwraca false
. jQuery i podkreślenie.js zapewniają własne wariacje na each
, aby zapewnić pętle, które mogą być zwarte.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-13 01:18:21
Jeśli chcesz zapętlić tablicę, użyj standardowej trzyczęściowej pętli for
.
for (var i = 0; i < myArray.length; i++) {
var arrayItem = myArray[i];
}
Możesz uzyskać kilka optymalizacji wydajności poprzez buforowanie myArray.length
lub iterację nad nim wstecz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-17 13:55:46
Jeśli nie masz nic przeciwko opróżnieniu tablicy:
var x;
while(x = y.pop()){
alert(x); //do something
}
x
będzie zawierać ostatnią wartość y
i zostanie usunięta z tablicy. Możesz również użyć shift()
, która da i usunie pierwszy element z y
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-30 18:37:32
Wiem, że to stary post, a jest już tak wiele świetnych odpowiedzi. Dla większej kompletności pomyślałem, że dorzucę jeszcze jedną używając AngularJS. Oczywiście, dotyczy to tylko jeśli używasz Angular, oczywiście, niemniej jednak chciałbym to ująć i tak.
angular.forEach
pobiera 2 argumenty i opcjonalny trzeci argument. Pierwszym argumentem jest obiekt (tablica) do iteracji, drugim argumentem jest funkcja iteratora, a opcjonalnym trzecim argumentem jest obiekt kontekst (w zasadzie określany wewnątrz pętli jako "this".
Istnieją różne sposoby wykorzystania pętli foreach kątowej. Najprostszym i prawdopodobnie najczęściej używanym jest
var temp = [1, 2, 3];
angular.forEach(temp, function(item) {
//item will be each element in the array
//do something
});
Innym sposobem, który jest przydatny do kopiowania elementów z jednej tablicy do drugiej jest
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);
Jednak nie musisz tego robić, możesz po prostu wykonać następujące czynności i jest to równoważne z poprzednim przykładem:]}
angular.forEach(temp, function(item) {
temp2.push(item);
});
Teraz są plusy i minusy używania funkcji angular.forEach
w przeciwieństwie do wbudowanej w pętli o smaku waniliowym for
.
Plusy
- łatwa czytelność
- łatwa pisownia
- jeśli jest dostępny,
angular.forEach
użyje pętli ES5 forEach. Teraz przejdę do efficiency w sekcji cons, ponieważ pętle forEach są dużo wolniejsze niż pętle for. Wspominam o tym jako profesjonalista, ponieważ miło jest być konsekwentnym i ustandaryzowanym.
Rozważ następujące 2 zagnieżdżone pętle, które robią dokładnie to samo. Powiedzmy, że my mają 2 tablice obiektów i każdy obiekt zawiera tablicę wyników, z których każdy ma właściwość Value, która jest ciągiem znaków (lub cokolwiek innego). I powiedzmy, że musimy iterować nad każdym z wyników i jeśli są równe, wykonaj jakąś akcję: {]}
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
}
}
}
Przyznaję, że jest to bardzo prosty hipotetyczny przykład, ale napisałem triple embedded dla pętli za pomocą drugiego podejścia i było to Bardzo trudne do odczytania i napisania Materia.
Cons
- efektywność.
angular.forEach
, a rodzimeforEach
, w tym przypadku, są zarównoo wiele wolniejsze niż normalnafor
pętla....o 90% wolniej . W przypadku dużych zbiorów danych najlepiej trzymać się natywnej pętlifor
. - brak wsparcia break, continue, lub return.
continue
jest rzeczywiście wspierany przez " wypadek", aby kontynuować wangular.forEach
wystarczy umieścićreturn;
w funkcji jakangular.forEach(array, function(item) { if (someConditionIsTrue) return; });
, co spowoduje, że kontynuuj z funkcji dla tej iteracji. Wynika to również z faktu, że natywnyforEach
również nie obsługuje break lub continue.
Jestem pewien, że są też inne plusy i minusy, i nie krępuj się dodawać dowolnych, które uznasz za odpowiednie. Czuję, że, podsumowując, jeśli potrzebujesz wydajności, trzymaj się tylko natywnej pętli for
dla swoich potrzeb pętli. Ale jeśli twoje zbiory danych są mniejsze i pewna wydajność jest w porządku, aby zrezygnować w zamian za czytelność i pisowalność, więc rzuć angular.forEach
w tego niegrzecznego chłopca.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-20 22:56:52
A forEach implementation (Zobacz w 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
}
);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-18 12:22:55
Od ECMAScript 6:
list = [0, 1, 2, 3]
for (let obj of list) {
console.log(obj)
}
Gdzie of
unika dziwności związanych z in
i sprawia, że działa jak pętla {[3] } dowolnego innego języka, a let
wiąże i
wewnątrz pętli w przeciwieństwie do funkcji.
Klamry ({}
) można pominąć, gdy istnieje tylko jedno polecenie (np. w powyższym przykładzie).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-12 05:12:07
Prawdopodobnie pętla for(i = 0; i < array.length; i++)
nie jest najlepszym wyborem. Dlaczego? Jeśli masz to:
var array = new Array();
array[1] = "Hello";
array[7] = "World";
array[11] = "!";
Metoda wywoła z array[0]
do array[2]
. Po pierwsze, spowoduje to odniesienie do zmiennych, których nawet nie masz, po drugie, nie będziesz miał zmiennych w tablicy, a po trzecie, spowoduje to, że kod będzie odważniejszy. Spójrz tutaj, to jest to, czego używam:
for(var i in array){
var el = array[i];
//If you want 'i' to be INT just put parseInt(i)
//Do something with el
}
I jeśli chcesz, aby to była funkcja, możesz to zrobić:
function foreach(array, call){
for(var i in array){
call(array[i]);
}
}
Jeśli chcesz złamać, trochę więcej logika:
function foreach(array, call){
for(var i in array){
if(call(array[i]) == false){
break;
}
}
}
Przykład:
foreach(array, function(el){
if(el != "!"){
console.log(el);
} else {
console.log(el+"!!");
}
});
Zwraca:
//Hello
//World
//!!!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-08 10:49:27
Istnieją trzy implementacje foreach
w jQuery w następujący sposób.
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-08 10:50:06
Łatwym rozwiązaniem byłoby teraz użycie podkreślenia .biblioteka js . Zapewnia wiele przydatnych narzędzi, takich jak {[1] } i automatycznie deleguje zadanie do natywnego forEach
, jeśli jest dostępne.
Przykład kodu Jak to działa to:
var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});
Zobacz też
-
Dokumentacja dla native
Array.prototype.forEach()
. - W for_each...in (MDN) wyjaśnia się, że
for each (variable in object)
jest przestarzały jako część ECMA-357 (EAX ) standard. -
dla...z (MDN) opisuje kolejny sposób iteracji używając
for (variable of object)
jako części propozycji Harmony (ECMAScript 6).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-30 22:23:09
Nie ma żadnej pętli for each
w natywnym JavaScript. Możesz użyć bibliotek, aby uzyskać tę funkcjonalność (polecam Underscore.js), użyj prostej {[3] } W pętli.
for (var instance in objects) {
...
}
Należy jednak pamiętać, że mogą być powody, aby użyć jeszcze prostszej pętli for
(Zobacz pytanie o przepełnienie stosuDlaczego jest za pomocą "for...in" z iteracją tablicy taki zły pomysł?)
var instance;
for (var i=0; i < objects.length; i++) {
var instance = objects[i];
...
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:36
Jest to iterator dla listy nieliniowej, gdzie indeks zaczyna się od 0, co jest typowym scenariuszem w przypadku dokumentu.getElementsByTagName lub 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;
Przykłady użycia:
Przykład #1
var arr = [];
[1, 2, 3].each( function(a){ a.push( this * this}, arr);
arr = [1, 4, 9]
Przykład #2
each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');
Każdy znacznik P dostaje class="blue"
Przykład #3
each.call(document.getElementsByTagName('p'),
"if( i % 2 == 0) this.className = data;",
'red'
);
Co drugi znacznik P dostaje class="red"
>
Przykład #4
each.call(document.querySelectorAll('p.blue'),
function(newClass, i) {
if( i < 20 )
this.className = newClass;
}, 'green'
);
I wreszcie pierwsze 20 niebieskich znaczników p zmienia się na zielone
Uwaga Podczas używania ciągu znaków jako funkcji: funkcja jest tworzona poza kontekstem i powinna być używana tylko wtedy, gdy masz pewność zakresu zmiennych. W przeciwnym razie lepiej przekazać funkcje, w których zasięg jest bardziej intuicyjny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-29 12:28:20
Istnieje kilka sposobów pętli przez tablicę w JavaScript, jak poniżej:
Dla - jest to najczęstszy. Pełny blok kodu do zapętlania
var languages = ["Java", "JavaScript", "C#", "Python"];
var i, len, text;
for (i = 0, len = languages.length, text = ""; i < len; i++) {
text += languages[i] + "<br>";
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>
While - pętla while warunek jest skończony. Wydaje się być najszybszą pętlą
var text = "";
var i = 0;
while (i < 10) {
text += i + ") something<br>";
i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>
Do / while - również Pętla przez blok kodu, gdy warunek jest true, będzie działać co najmniej one time
var text = ""
var i = 0;
do {
text += i + ") something <br>";
i++;
}
while (i < 10);
document.getElementById("example").innerHTML = text;
<p id="example"></p>
Pętle funkcjonalne - forEach
, map
, filter
, również reduce
(pętli przez funkcję, ale są one używane, jeśli trzeba zrobić coś z tablicy, itp.
// For example, in this case we loop through the number and double them up using the map function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>
Aby uzyskać więcej informacji i przykładów na temat programowania funkcyjnego na tablicach, zajrzyj do wpisu na bloguprogramowanie funkcjonalne w JavaScript: mapowanie, filtrowanie i redukowanie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-22 23:32:48
ECMAScript 5 (Wersja Na JavaScript) do pracy z tablicami:
ForEach - iteruje każdy element w tablicy i robi z każdym elementem wszystko, czego potrzebujesz.
['C', 'D', 'E'].forEach(function(element, index) {
console.log(element + " is #" + (index+1) + " in the musical scale");
});
// Output
// C is the #1 in musical scale
// D is the #2 in musical scale
// E is the #3 in musical scale
W przypadku, bardziej zainteresowany działaniem na tablicy przy użyciu jakiejś wbudowanej funkcji.
Map - tworzy nową tablicę z wynikiem funkcji callback. Ta metoda jest dobra do użycia, gdy trzeba sformatować elementy tablicy.
// Let's upper case the items in the array
['bob', 'joe', 'jen'].map(function(elem) {
return elem.toUpperCase();
});
// Output: ['BOB', 'JOE', 'JEN']
Reduce - jako nazwa mówi, że zmniejsza tablicę do pojedynczej wartości przez wywołanie danej funkcji przechodzącej w bieżącym elemencie i wyniku poprzedniego wykonania.
[1,2,3,4].reduce(function(previous, current) {
return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10
Every - zwraca true lub false, jeśli wszystkie elementy w tablicy przeszły test w funkcji callback.
// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];
ages.every(function(elem) {
return elem >= 18;
});
// Output: false
Filter - bardzo podobny do każdego z wyjątkiem, że filtr zwraca tablicę z elementami, które zwracają true do podanej funkcji.
// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
return (elem % 2 == 0)
});
// Output: [2,4,6]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-03 20:55:31
Nie ma wbudowanej możliwości włamania się forEach
. Aby przerwać wykonanie użyj Array#some
Jak poniżej:
[1,2,3].some(function(number) {
return number === 1;
});
To działa, ponieważ some
zwraca true tak szybko, jak każde wywołanie zwrotne, wykonane w kolejności tablicy, zwraca true, co powoduje zwarcie wykonania reszty.
Oryginalna Odpowiedź
zobacz prototyp tablicy dla niektórych
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:59
Chciałbym również dodać to jako kompozycję odwrotnej pętli i odpowiedź powyżej dla kogoś, kto chciałby tę składnię też.
var foo = [object,object,object];
for (var i = foo.length, item; item = foo[--i];) {
console.log(item);
}
Plusy:
Korzyści z tego: masz referencję już w pierwszym, jak, że nie będzie musiał być zadeklarowany później z innej linii. Jest to przydatne przy zapętlaniu przez tablicę obiektów.
Wady:
Zostanie przerwane, gdy Referencja będzie false-False (undefined, etc.). Może być stosowany jako ale przewaga. Byłoby to jednak nieco trudniejsze do odczytania. A także w zależności od przeglądarki można go "nie" zoptymalizować, aby działał szybciej niż oryginalna.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-28 16:08:21
JQuery way using $.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];
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-01 11:15:26
Używanie pętli z operatorem rozproszonym ECMAScript 6 destrukcji i
Destrukcja i użycie operatora rozprzestrzeniania okazały się dość przydatne dla początkujących w ECMAScript 6 jako bardziej czytelny / estetyczny, chociaż niektórzy weterani JavaScript mogą uznać to za bałagan. Juniorzy lub inni ludzie mogą uznać to za przydatne.
Poniższe przykłady będą używać
for...of
oświadczenie i.forEach
metoda.Przykłady 6, 7 i 8 mogą być używane z dowolnymi pętlami funkcyjnymi, takimi jak
.map
,.filter
,.reduce
,.sort
,.every
,.some
. Więcej informacji na temat tych metod można znaleźć w obiekcie Array .
Przykład 1: Normal for...of
loop-żadnych sztuczek.
let arrSimple = ['a', 'b', 'c'];
for (let letter of arrSimple) {
console.log(letter);
}
Przykład 2: podziel słowa na znaki
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);
}
Przykład 3: zapętlenie za pomocą key
i value
// let arrSimple = ['a', 'b', 'c'];
// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`
// this example will use a multi-dimensional array of the following format type:
// `arrWithIndex: [number, string][]`
let arrWithIndex = [
[0, 'a'],
[1, 'b'],
[2, 'c'],
];
// Same thing can be achieved using `.map` method
// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);
// Same thing can be achieved using `Object.entries`
// NOTE: `Object.entries` method doesn't work on Internet Explorer unless it's polyfilled
// let arrWithIndex = Object.entries(arrSimple);
for (let [key, value] of arrWithIndex) {
console.log(key, value);
}
Przykład 4: Get object properties inline
let arrWithObjects = [{
name: 'Jon',
age: 32
},
{
name: 'Elise',
age: 33
}
];
for (let { name, age: aliasForAge } of arrWithObjects) {
console.log(name, aliasForAge);
}
Przykład 5: Get deep object properties of what you need
let arrWithObjectsWithArr = [{
name: 'Jon',
age: 32,
tags: ['driver', 'chef', 'jogger']
},
{
name: 'Elise',
age: 33,
tags: ['best chef', 'singer', 'dancer']
}
];
for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
console.log(name, firstItemFromTags, restOfTags);
}
Przykład 6: to przykład 3 używany z .forEach
let arrWithIndex = [
[0, 'a'],
[1, 'b'],
[2, 'c'],
];
// Not to be confused here, `forEachIndex` is the real index
// `mappedIndex` was created by "another user", so you can't really trust it
arrWithIndex.forEach(([mappedIndex, item], forEachIndex) => {
console.log(forEachIndex, mappedIndex, item);
});
Przykład 7: to przykład 4 używany z .forEach
let arrWithObjects = [{
name: 'Jon',
age: 32
},
{
name: 'Elise',
age: 33
}
];
// NOTE: Destructuring objects while using shorthand functions
// are required to be surrounded by parentheses
arrWithObjects.forEach( ({ name, age: aliasForAge }) => {
console.log(name, aliasForAge)
});
Przykład 8: To Przykład 5 używane z .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);
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55
Najbardziej zbliżonym sposobem do twojego pomysłu byłoby użycie Array.forEach()
, które akceptuje funkcję zamknięcia, która będzie wykonywana dla każdego elementu tablicy.
myArray.forEach(
(item) => {
// Do something
console.log(item);
}
);
Innym realnym sposobem byłoby użycie Array.map()
, które działa w ten sam sposób, ale również pobiera wszystkie zwracane wartości i zwraca je w nowej tablicy( zasadniczo mapowanie każdego elementu na nowy), Tak:
var myArray = [1, 2, 3];
myArray = myArray.map(
(item) => {
return item + 1;
}
);
console.log(myArray); // [2, 3, 4]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-04 17:51:03
Składnia lambda zwykle nie działa w Internet Explorerze 10 lub poniżej.
Zwykle używam
[].forEach.call(arrayName,function(value,index){
console.log("value of the looped element" + value);
console.log("index of the looped element" + index);
});
Jeśli jesteś fanem jQuery i masz już uruchomiony plik jQuery, powinieneś odwrócić pozycje parametrów indeksu i wartości
$("#ul>li").each(function(**index, value**){
console.log("value of the looped element" + value);
console.log("index of the looped element" + index);
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-03 20:36:46
Możesz wywołać forEach Tak:
forEach
będzie iteracją nad podaną tablicą i dla każdej iteracji będzie miała element
, która przechowuje wartość tej iteracji. Jeśli potrzebujesz indeksu, możesz uzyskać bieżący indeks, przekazując i
jako drugi parametr w funkcji callback dla forEach.
Foreach jest zasadniczo funkcją wysokiego rzędu, która przyjmuje inną funkcję jako swój parametr.
let theArray= [1,3,2];
theArray.forEach((element) => {
// Use the element of the array
console.log(element)
}
Wyjście:
1
3
2
Można również iterację nad tablicą taką jak to:
for (let i=0; i<theArray.length; i++) {
console.log(i); // i will have the value of each index
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-25 12:13:35
Jeśli chcesz użyć forEach()
, będzie to wyglądało tak: -
theArray.forEach ( element => {
console.log(element);
});
Jeśli chcesz użyć for()
, będzie to wyglądało tak: -
for(let idx = 0; idx < theArray.length; idx++){
let element = theArray[idx];
console.log(element);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-04 23:18:22
Jeśli chcesz zapętlić tablicę obiektów za pomocą funkcji strzałki:
let arr = [{name:'john', age:50}, {name:'clark', age:19}, {name:'mohan', age:26}];
arr.forEach((person)=>{
console.log('I am ' + person.name + ' and I am ' + person.age + ' old');
})
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-03 20:04:07
Wydajność
Dzisiaj (2019-12-18) wykonuję test na moim macOS v10.13.6 (High Sierra), Na Chrome v 79.0, Safari v13.0. 4 i Firefox v71. 0 (64 bit) - wnioski dotyczące optymalizacji (i mikro-optymalizacja co zwykle nie warto wprowadzać go do kodu, ponieważ korzyści są niewielkie, ale złożoność kodu rośnie).
Wygląda jak tradycyjny
for i
(Aa ) jest dobrym wyborem do napisania szybkiego kodu na wszystkich przeglądarki.Inne rozwiązania, takie jak
for-of
(Ad), wszystkie w grupie C. ... są zwykle 2-10 (i więcej) razy wolniejsze niż Aa , ale w przypadku małych tablic można ich używać - dla zwiększenia przejrzystości kodu.Pętle o długości tablicy w pamięci podręcznej
n
(Ab, Bb, Be) są czasem szybsze, czasem nie. Prawdopodobnie Kompilatory automatycznie wykrywają tę sytuację i wprowadzają buforowanie. Różnice prędkości między wersje cached i no-cached ( Aa, Ba, Bd ) są około ~1%, więc wygląda na to, że introducen
jest mikro-optymalizacja.i--
podobne rozwiązania, w których pętla zaczyna się od ostatniego elementu tablicy ( Ac, BC ) są zwykle ~30% wolniejsze od rozwiązań forward - prawdopodobnie powodem jest sposób działania pamięci podręcznej CPU - odczyt pamięci forward jest bardziej optymalny dla buforowania CPU). zaleca się, aby nie używać takich rozwiązania.
Szczegóły
W testach obliczamy sumę elementów tablicy. Wykonuję test dla małych tablic (10 elementów) i dużych tablic (1m elementów) i dzielę je na trzy grupy:
-
A -
for
testy -
B -
while
testy - C - inne / alternatywne metody
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
//let arr = Array.from(Array(1000000), (x, i) => i%10);
function Aa(a, s=0) {
for(let i=0; i<a.length; i++) {
s += a[i];
}
console.log('Aa=', s);
}
function Ab(a, s=0) {
let n = a.length;
for(let i=0; i<n; i++) {
s += a[i];
}
console.log('Ab=', s);
}
function Ac(a, s=0) {
for(let i=a.length; i--;) {
s += a[i];
}
console.log('Ac=', s);
}
function Ad(a, s=0) {
for(let x of a) {
s += x;
}
console.log('Ad=', s);
}
function Ae(a, s=0) {
for(let i in a) if (a.hasOwnProperty(i)) {
s += a[i];
}
console.log('Ae=', s);
}
function Ba(a, s=0) {
let i = -1;
while(++i < a.length) {
s+= a[i];
}
console.log('Ba=', s);
}
function Bb(a, s=0) {
let i = -1;
let n = a.length;
while(++i < n) {
s+= a[i];
}
console.log('Bb=', s);
}
function Bc(a, s=0) {
let i = a.length;
while(i--) {
s += a[i];
}
console.log('Bc=', s);
}
function Bd(a, s=0) {
let i = 0;
do {
s+= a[i]
} while (++i < a.length);
console.log('Bd=', s);
}
function Be(a, s=0) {
let i = 0;
let n = a.length;
do {
s += a[i]
} while (++i < n);
console.log('Be=', s);
}
function Bf(a, s=0) {
const it = a.values();
let e;
while (!(e = it.next()).done) {
s+= e.value;
}
console.log('Bf=', s);
}
function Ca(a, s=0) {
a.map(x => { s+=x });
console.log('Ca=', s);
}
function Cb(a, s=0) {
a.forEach(x => { s+=x });
console.log('Cb=', s);
}
function Cc(a, s=0) {
a.every(x => (s += x, 1));
console.log('Cc=', s);
}
function Cd(a, s=0) {
a.filter(x => { s+=x });
console.log('Cd=',s);
}
function Ce(a, s=0) {
a.reduce((z, c) => { s+=c }, 0);
console.log('Ce=', s);
}
function Cf(a, s=0) {
a.reduceRight((z, c) => { s += c }, 0);
console.log('Cf=', s);
}
function Cg(a, s=0) {
a.some(x => { s += x } );
console.log('Cg=', s);
}
function Ch(a, s=0) {
Array.from(a, x=> s += x);
console.log('Cc=', s);
}
Aa(arr);
Ab(arr);
Ac(arr);
Ad(arr);
Ae(arr);
Ba(arr);
Bb(arr);
Bc(arr);
Bd(arr);
Be(arr);
Bf(arr);
Ca(arr);
Cb(arr);
Cc(arr);
Cd(arr);
Ce(arr);
Cf(arr);
Cg(arr);
Ch(arr);
<p style="color: red">This snippets only PRESENTS code used for benchmark - it not perform test itself</p>
Cross browser results
Wyniki dla wszystkich badanych przeglądarki
Tablica z 10 elementami
Wyniki dla Chrome. Możesz wykonać test na swojej maszynie tutaj .
Tablica z 1 000 000 elementów
Wyniki dla Chrome. Możesz wykonać test na swojej maszynie tutaj
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-08 19:17:34
Jeśli masz masywną tablicę powinieneś użyć iterators
aby zyskać trochę wydajności. Iteratory są własnością pewnych kolekcji JavaScript (jak Map
, Set
, String
, Array
). Parzyste, for..of
zastosowania iterator
pod maską.
Dostęp do bieżącego elementu można uzyskać, wywołując metodę iteratora next
. Następna metoda zwróci value
bieżącej pozycji oraz boolean
aby wskazać, kiedy dotarłeś do końca kolekcji. Poniżej przedstawiono przykład tworzenia iteratora z tablicy.
Przekształć zwykłą tablicę w iterator używając values()
metoda jak ta:
const myArr = [2,3,4]
let it = myArr.values();
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
Możesz również przekształcić zwykłą tablicę do iteratora za pomocą Symbol.iterator
tak:
const myArr = [2,3,4]
let it = myArr[Symbol.iterator]();
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
Możesz również przekształcić swoje zwykłe array
W iterator
tak:
let myArr = [8, 10, 12];
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{done: true};
}
};
};
var it = makeIterator(myArr);
console.log(it.next().value); // {value: 8, done: false}
console.log(it.next().value); // {value: 10, done: false}
console.log(it.next().value); // {value: 12, done: false}
console.log(it.next().value); // {value: undefined, done: true}
Uwaga :
- Iteratory są wyczerpujące w naturze.
- obiekty nie są domyślnie
iterable
. Użyciefor..in
W takim przypadku, ponieważ zamiast wartości działa z kluczami.
Możesz przeczytać więcej o iteration protocol
tutaj .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-06 11:32:03
Zgodnie z nową, zaktualizowaną funkcją ECMAScript 6 (ES6) i ECMAScript 2015, możesz używać następujących opcji z pętlami:
Dla pętli
for(var i = 0; i < 5; i++){
console.log(i);
}
// Output: 0,1,2,3,4
For...in pętle
let obj = {"a":1, "b":2}
for(let k in obj){
console.log(k)
}
// Output: a,b
/ align = "left" / forEach()
let array = [1,2,3,4]
array.forEach((x) => {
console.log(x);
})
// Output: 1,2,3,4
Za...of loops
let array = [1,2,3,4]
for(let x of array){
console.log(x);
}
// Output: 1,2,3,4
Pętle While
let x = 0
while(x < 5){
console.log(x)
x++
}
// Output: 1,2,3,4
Zrób...pętle while
let x = 0
do{
console.log(x)
x++
}while(x < 5)
// Output: 1,2,3,4
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-08 14:51:36
Podsumowanie:
Kiedy iterację nad tablicą chcemy osiągnąć jeden z następujących celów:]}-
Chcemy iterację nad tablicą i utworzyć nową tablicę:
Array.prototype.map
-
Chcemy iterację nad tablicą i nie tworzyć nowej tablicy:
Array.prototype.forEach
for..of
pętla
W JavaScript istnieje wiele sposobów osiągnięcia obu tych celów. Jednak niektóre z nich są bardziej wygodne niż inne. Poniżej znajdziesz kilka powszechnie używanych metod (najwygodniejsza IMO) do wykonania iteracji tablicy w JavaScript.
Tworzenie nowej tablicy: Map
map()
jest funkcją znajdującą się na Array.prototype
, która może przekształcić każdy element tablicy, a następnie zwraca nową tablicę. map()
przyjmuje jako argument funkcję zwrotną i działa w następujący sposób:
let arr = [1, 2, 3, 4, 5];
let newArr = arr.map((element, index, array) => {
return element * 2;
})
console.log(arr);
console.log(newArr);
Wywołanie zwrotne, które przekazaliśmy map()
jako argument jest wykonywany dla każdego elementu. Następnie zwracana jest tablica, która ma taką samą długość jak oryginalna tablica. W tej nowej tablicy element jest przekształcany przez funkcję wywołania zwrotnego przekazaną jako argument do map()
.
Różnica pomiędzy map
a innym mechanizmem pętli, takim jak forEach
i for..of
jest taka, żemap
zwraca nową tablicę i pozostawia starą tablicę nienaruszoną (chyba że jawnie manipulujesz nią za pomocą myśli splice
).
Uwaga że wywołanie zwrotne funkcji map
dostarcza Numer indeksu bieżącej iteracji jako drugi argument. Co więcej, czy trzeci argument dostarcza tablicy, na której map
został wywołany? Czasami te właściwości mogą być bardzo przydatne.
Pętla za pomocą forEach
forEach
jest funkcją znajdującą się na Array.prototype
, która przyjmuje funkcję zwrotną jako argument. Następnie wykonuje tę funkcję zwrotną dla każdego elementu w tablicy. W przeciwieństwie do funkcji map()
, forEach funkcja nie zwraca nic (undefined
). Na przykład:
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);
Podobnie jak funkcja map
, wywołanie zwrotne forEach
dostarcza Numer indeksu bieżącej iteracji jako drugi argument. Czy trzeci argument dostarcza tablicy, na której forEach
został wywołany?
Pętla przez elementy za pomocą for..of
Pętla for..of
przenika przez każdy element tablicy (lub inny obiekt iteracyjny). Działa w następujących sposób:
let arr = [1, 2, 3, 4, 5];
for(let element of arr) {
console.log(element * 2);
}
W powyższym przykładzie, element
oznacza element tablicy, a {[31] } jest tablicą, którą chcemy zapętlić. Zauważ, że nazwa element
jest dowolna i mogliśmy wybrać dowolną inną nazwę, taką jak ' el ' lub coś bardziej deklaratywnego, gdy ma to zastosowanie.
Nie myl pętli for..in
z pętlą for..of
. for..in
będzie w pętli przez wszystkie właściwości tablicy, podczas gdy pętla for..of
będzie w pętli tylko przez elementy tablicy. Na przykład:
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);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-28 18:11:58