Widziałem ostatnie pytanie, w którym ktoś ci to powiedział, ale chodziło tylko o tablice. Uważa się, że jest to zła praktyka w przypadku iteracji przez tablice, ale niekoniecznie w przypadku iteracji przez elementy obiektu.
mmurch
19
Wiele odpowiedzi zawierających pętle „for”, takie jak „for (var i = 0; i <hColl.length; i ++) {}” w porównaniu do „var i = hColl.length; natomiast (i--) {} ', który, gdy można użyć tej drugiej formy, jest znacznie szybszy. Wiem, że to styczne, ale pomyślałem, że mógłbym to dodać.
Mark Schultheiss,
2
@MarkSchultheiss, ale to odwrotna iteracja. Czy istnieje inna wersja iteracji do przodu, która jest szybsza?
ma11hew28,
5
@Wynand używa var i = hCol1.length; for (i;i;i--;) {}pamięci podręcznej i, ponieważ będzie to miało znaczenie i uprości test. - im starsza przeglądarka, tym większa różnica między fori whileZAWSZE buforuje licznik „i” - i oczywiście negatywne nie zawsze pasuje do sytuacji, a negatywne, podczas obfuscate gdy kod trochę dla niektórych osób. i zwróć uwagę, var i = 1000; for (i; i; i--) {}a var b =1000 for (b; b--;) {}gdzie i idzie od 1000 do 1, a b od 999 do 0. - im starsza przeglądarka, tym bardziej sprzyja wydajności.
Mark Schultheiss
9
Możesz także być sprytny. for(var i = 0, l = myArray.length; i < l; ++i) ...jest najszybszym i najlepszym, jakie można uzyskać dzięki iteracji do przodu.
Mathieu Amiot
Odpowiedzi:
1557
Powodem jest to, że jeden konstrukt:
var a =[];// Create a new empty array.
a[5]=5;// Perfectly legal JavaScript that resizes the array.for(var i =0; i < a.length; i++){// Iterate over numeric indexes from 0 to 5, as everyone expects.
console.log(a[i]);}/* Will display:
undefined
undefined
undefined
undefined
undefined
5
*/
Weź również pod uwagę, że biblioteki JavaScript mogą robić takie rzeczy, co wpłynie na każdą utworzoną tablicę:
// Somewhere deep in your JavaScript library...Array.prototype.foo =1;// Now you have no idea what the below code will do.var a =[1,2,3,4,5];for(var x in a){// Now foo is a part of EVERY array and // will show up here as a value of 'x'.
console.log(x);}/* Will display:
0
1
2
3
4
foo
*/
Historycznie niektóre przeglądarki powtarzały nawet „długość”, „toString” itd.!
bobince
398
Pamiętaj, aby używać (var x in a)zamiast (x in a)- nie chcę tworzyć globalnego.
Chris Morgan,
78
Pierwszy problem nie jest powodem, dla którego jest zły, tylko różnica w semantyce. Drugi problem wydaje mi się powodem (poza konfliktami między bibliotekami, które robią to samo), że zmiana prototypu wbudowanego typu danych jest zła, a nie zła dla… in.
Stewart
86
@Stewart: Wszystkie obiekty w JS są asocjacyjne. Tablica JS jest obiektem, więc tak, jest również skojarzona, ale nie po to jest. Jeśli chcesz iterować klucze obiektu , użyj for (var key in object). Jeśli jednak chcesz iterować elementy tablicy , użyj for(var i = 0; i < array.length; i += 1).
Martijn
42
W pierwszym przykładzie powiedziałeś, że iteruje ponad indeksy numeryczne od 0 do 4, jak wszyscy się spodziewają , oczekuję, że iteruje od 0 do 5 ! Ponieważ jeśli dodasz element w pozycji 5, tablica będzie miała 6 elementów (5 z nich jest niezdefiniowanych).
stivlo
393
Samo for-instwierdzenie nie jest „złą praktyką”, jednak może być niewłaściwie użyte , na przykład do iteracji po tablicach lub obiektach podobnych do tablic.
Celem for-ininstrukcji jest wyliczenie właściwości obiektu. To oświadczenie wejdzie w górę w łańcuchu prototypów, wyliczając również odziedziczone właściwości, co czasami nie jest pożądane.
Ponadto specyfikacja nie gwarantuje kolejności iteracji, co oznacza, że jeśli chcesz „iterować” obiekt tablicowy, dzięki tej instrukcji nie możesz być pewien, że właściwości (indeksy tablicowe) będą odwiedzane w kolejności numerycznej.
Na przykład w JScript (IE <= 8) kolejność wyliczania nawet w obiektach Array jest definiowana w miarę tworzenia właściwości:
var array =[];
array[2]='c';
array[1]='b';
array[0]='a';for(var p in array){//... p will be "2", "1" and "0" on IE}
Mówiąc również o odziedziczonych właściwościach, jeśli na przykład rozszerzysz Array.prototypeobiekt (jak niektóre biblioteki, jak robią to MooTools), właściwości te zostaną również wyliczone:
Array.prototype.last =function(){returnthis[this.length-1];};for(var p in []){// an empty array// last will be enumerated}
Jak powiedziałem wcześniej, aby iterować po tablicach lub obiektach podobnych do tablic, najlepszą rzeczą jest użycie pętli sekwencyjnej , takiej jak zwykła for/ whilepętla.
Jeśli chcesz wyliczyć tylko własne właściwości obiektu (te, które nie są dziedziczone), możesz użyć hasOwnPropertymetody:
for(var prop in obj){if(obj.hasOwnProperty(prop)){// prop is not inherited}}
Niektórzy nawet zalecają bezpośrednie wywołanie metody, Object.prototypeaby uniknąć problemów, jeśli ktoś doda właściwość o nazwie hasOwnPropertydo naszego obiektu:
for(var prop in obj){if(Object.prototype.hasOwnProperty.call(obj, prop)){// prop is not inherited}}
Pytanie o ostatni punkt na temat „hasOwnProperty”: Jeśli ktoś zastąpi „hasOwnProperty” na obiekcie, będziesz mieć problemy. Ale czy nie będziesz mieć takich samych problemów, jeśli ktoś zastąpi „Object.prototype.hasOwnProperty”? Tak czy inaczej to cię psują i to nie twoja odpowiedzialność, prawda?
Scott Rippey,
Mówisz, że for..innie jest to zła praktyka, ale może być nadużywana. Czy masz przykład dobrej praktyki z prawdziwego świata, w którym naprawdę chciałeś przejrzeć wszystkie właściwości obiektów, w tym właściwości odziedziczone?
z tą odpowiedzią stwierdziłem, że można uzyskać dostęp do wartości za pomocąfor (var p in array) { array[p]; }
equiman
117
Istnieją trzy powody, dla których nie powinieneś for..initerować elementów tablicy:
for..inzapętli wszystkie własne i odziedziczone właściwości obiektu tablicy, które nie są DontEnum; oznacza to, że jeśli ktoś doda właściwości do konkretnego obiektu tablicy (istnieją uzasadnione powody - sam to zrobiłem) lub zmieniłem Array.prototype(co jest uważane za złą praktykę w kodzie, który powinien działać dobrze z innymi skryptami), właściwości te będą powtarzać się również; odziedziczone właściwości można wykluczyć poprzez sprawdzenie hasOwnProperty(), ale to nie pomoże ci z właściwościami ustawionymi w samym obiekcie tablicy
for..in nie gwarantuje się zachowania kolejności elementów
jest powolny, ponieważ musisz przejść wszystkie właściwości obiektu tablicy i całego jego łańcucha prototypów i nadal otrzyma tylko nazwę właściwości, tj. aby uzyskać wartość, konieczne będzie dodatkowe wyszukiwanie
Ponieważ dla ... w wylicza przez obiekt, który zawiera tablicę, a nie samą tablicę. Jeśli dodam funkcję do łańcucha prototypów tablic, zostanie to również uwzględnione. To znaczy
Array.prototype.myOwnFunction =function(){ alert(this);}
a =newArray();
a[0]='foo';
a[1]='bar';for(x in a){
document.write(x +' = '+ a[x]);}
Tablice są obiektami, nie ma „obiektu, który trzyma tablicę”.
RobG
41
W izolacji nie ma nic złego w korzystaniu z for-in na tablicach. I-in iteruje nazwy właściwości obiektu, aw przypadku tablicy „out-of-the-box” właściwości odpowiadają indeksom tablic. (Wbudowany propertes podobnych length, toStringa więc nie są wliczone w iteracji).
Jeśli jednak Twój kod (lub używana struktura) doda niestandardowe właściwości do tablic lub do prototypu tablicy, właściwości te zostaną uwzględnione w iteracji, co prawdopodobnie nie jest tym, czego chcesz.
Niektóre frameworki JS, takie jak Prototype, modyfikują prototyp Array. Inne frameworki, takie jak JQuery, nie mają, więc z JQuery można bezpiecznie używać dla.
Jeśli masz wątpliwości, prawdopodobnie nie powinieneś używać for-in.
Alternatywnym sposobem iteracji po tablicy jest użycie pętli for:
for(var ix=0;ix<arr.length;ix++) alert(ix);
Ma to jednak inny problem. Problem polega na tym, że tablica JavaScript może mieć „dziury”. Jeśli zdefiniujesz arrjako:
var arr =["hello"];
arr[100]="goodbye";
Następnie tablica ma dwa elementy, ale długość 101. Użycie for-in da dwa indeksy, podczas gdy pętla for da 101 indeksów, gdzie 99 ma wartość undefined.
Dłuższa odpowiedź: po prostu nie jest tego warte, nawet jeśli kolejność elementów sekwencyjnych i optymalna wydajność nie są wymagane.
Długa odpowiedź: po prostu nie warto ...
Użycie for (var property in array)spowoduje arrayiterację jako obiekt , przemieszczenie łańcucha prototypów obiektu i ostatecznie działanie wolniejsze niż forpętla oparta na indeksie .
for (... in ...) nie gwarantuje się zwrócenia właściwości obiektu w kolejności sekwencyjnej, jak można się spodziewać.
Używanie hasOwnProperty()i !isNaN()sprawdzanie do filtrowania właściwości obiektu jest dodatkowym narzutem, który powoduje, że działa jeszcze wolniej i neguje kluczowy powód używania go w pierwszej kolejności, tj. Z powodu bardziej zwięzłego formatu.
Z tych powodów akceptowalny kompromis między wydajnością a wygodą nawet nie istnieje. Naprawdę nie ma korzyści, chyba że celem jest obsługa tablicy jako obiektu i wykonywanie operacji na właściwościach obiektu tablicy.
Oprócz powodów podanych w innych odpowiedziach, możesz nie chcieć używać struktury „for ... in”, jeśli musisz wykonać matematykę ze zmienną licznika, ponieważ pętla iteruje nazwy właściwości obiektu, a więc zmienna jest ciągiem.
Możesz użyć prefiksu +zamiast, parseIntchyba że naprawdę potrzebujesz liczby całkowitej lub zignoruj nieprawidłowe znaki.
Konrad Borowski
Używanie parseInt()nie jest również zalecane. Spróbuj parseInt("025");i to będzie zawieść.
Derek 朕 會 功夫
6
@Derek 朕 會 功夫 - zdecydowanie możesz użyć parseInt. Problem polega na tym, że jeśli nie dodasz podstawki, starsze przeglądarki mogą próbować zinterpretować liczbę (w ten sposób 025 staje się ósemkowa). Zostało to naprawione w ECMAScript 5, ale nadal występuje w przypadku liczb rozpoczynających się od „0x” (interpretuje liczbę jako szesnastkową). Aby być po bezpiecznej stronie, użyj podstawy, aby określić liczbę w ten sposób parseInt("025", 10)- która określa podstawę 10.
Mechanika i kolejność wyliczania właściwości ... nie jest określona ...
(Podkreśl moje.)
Oznacza to, że jeśli przeglądarka tego chce, może przeglądać właściwości w kolejności, w jakiej zostały wstawione. Lub w kolejności numerycznej. Lub w porządku leksykalnym (gdzie „30” występuje przed „4”! Pamiętaj, że wszystkie klucze obiektów - a zatem wszystkie indeksy tablic - są w rzeczywistości łańcuchami, więc to ma sens). Mógłby je przeglądać za pomocą segmentu, jeśli zaimplementował obiekty jako tabele skrótów. Lub weź dowolny z nich i dodaj „wstecz”. Przeglądarka może nawet iterować losowo i być zgodna z ECMA-262, o ile odwiedza każdą właściwość dokładnie raz.
W praktyce większość przeglądarek lubi iterować mniej więcej w tej samej kolejności. Ale nic nie mówi, że muszą. Jest to specyficzne dla implementacji i może ulec zmianie w dowolnym momencie, jeśli okaże się, że inny sposób jest znacznie bardziej wydajny.
Tak czy inaczej for... inniesie ze sobą żadnego związku z porządkiem. Jeśli zależy Ci na porządku, wypowiedz się o nim i użyj zwykłej forpętli z indeksem.
Jak powiedzieli inni, możesz dostać klucze, które nie są w twojej tablicy lub są dziedziczone z prototypu. Więc jeśli, powiedzmy, biblioteka dodaje właściwość do prototypów Array lub Object:
Array.prototype.someProperty =true
Otrzymasz to jako część każdej tablicy:
for(var item in [1,2,3]){
console.log(item)// will log 1,2,3 but also "someProperty"}
możesz to rozwiązać za pomocą metody hasOwnProperty:
var ary =[1,2,3];for(var item in ary){if(ary.hasOwnProperty(item)){
console.log(item)// will log only 1,2,3}}
ale dotyczy to iteracji po dowolnym obiekcie z pętlą for-in.
Dwa
Zwykle kolejność elementów w tablicy jest ważna, ale pętla for-in niekoniecznie iteruje we właściwej kolejności, ponieważ traktuje tablicę jako obiekt, tak jak jest implementowana w JS, a nie jako tablica. Wydaje się, że to drobiazg, ale naprawdę może zepsuć aplikacje i jest trudny do debugowania.
Object.keys(a).forEach( function(item) { console.log(item) } )iteruje tablicę własnych kluczy własności, a nie tych odziedziczonych po prototypie.
Qwerty
2
To prawda, ale podobnie jak w przypadku pętli for-in, niekoniecznie musi być w odpowiedniej kolejności indeksu. Nie działa również w starszych przeglądarkach nieobsługujących ES5.
Więc jaki jest najlepszy sposób na zrobienie tego?
lYriCAlsSH
3
for (var i = 0; i <arr.length; i ++) {}
vava
3
W Firefoksie 3 możesz także użyć arr.forEach lub for (var [i, v] w Iterator (arr)) {}, ale żaden z nich nie działa w IE, chociaż możesz samodzielnie napisać metodę forEach.
vava
i praktycznie każda biblioteka ma też własną metodę.
vava
5
Ta odpowiedź jest zła. „długość” nie będzie uwzględniana w iteracji wstępnej. Uwzględnione są tylko właściwości, które sam dodajesz.
Chciałbym jednak dodać, że we współczesnych przeglądarkach istnieje alternatywa, z for...inktórej można korzystać w przypadkach, gdy for...innie można jej użyć. Ta alternatywa to for...of:
for(var item of items){
console.log(item);}
Uwaga :
Niestety żadna wersja programu Internet Explorer nie obsługuje for...of( Edge 12+ ), więc musisz poczekać trochę dłużej, aż będziesz mógł użyć go w kodzie produkcyjnym po stronie klienta. Jednak użycie kodu JS po stronie serwera powinno być bezpieczne (jeśli używasz Node.js ).
@georgeawg Miałeś na myśli for-ofnie for-in, prawda?
ᆼ ᆺ ᆼ
15
Problem z for ... in ...- a staje się to problemem tylko wtedy, gdy programista tak naprawdę nie rozumie języka; tak naprawdę nie jest to błąd ani nic takiego - polega na tym, że iteruje wszystkie elementy obiektu (cóż, wszystkie elementy policzalne , ale na razie jest to szczegół). Jeśli chcesz iterować tylko indeksowane właściwości tablicy, jedynym gwarantowanym sposobem na zachowanie spójności semantycznej jest użycie indeksu liczb całkowitych (to znaczy for (var i = 0; i < array.length; ++i)pętli stylów).
Każdy obiekt może mieć dowolne właściwości z nim związane. W szczególności nie byłoby nic strasznego w ładowaniu dodatkowych właściwości do instancji tablicy. Kod, który chce widzieć tylko indeksowane właściwości podobne do tablic, musi zatem trzymać się indeksu liczb całkowitych. Kod, który jest w pełni świadomy tego, co for ... inrobi i naprawdę musi zobaczyć wszystkie właściwości, to też w porządku.
Ładne wyjaśnienie Pointy. Po prostu ciekawy. Gdybym miał tablicę, która znajdowała się w obiekcie pod właściwościami mnożenia i czy for inw porównaniu do zwykłej pętli for tablice te zostałyby iterowane? (co w gruncie rzeczy byłoby wolne, prawda?)
NiCk Newman
2
@NiCkNewman dobrze obiekt, do którego się odwołujesz inw for ... inpętli, po prostu
Pointy
Widzę. Ciekawe, ponieważ mam obiekty i tablice wewnątrz mojego głównego obiektu gry i zastanawiałem się, czy dla inningu byłoby to bardziej bolesne niż zwykła pętla for dla indeksów.
NiCk Newman
@NiCkNewman dobrze tematem całego tego pytania jest to, że po prostu nie powinieneś używać for ... inna tablicach; istnieje wiele dobrych powodów, aby tego nie robić. To nie tyle problem z wydajnością, co problem „upewnij się, że się nie złamie”.
Pointy
Cóż, moje obiekty są technicznie przechowywane w tablicy, dlatego się martwiłem, coś w stylu [{a:'hey',b:'hi'},{a:'hey',b:'hi'}]:, ale tak, rozumiem.
NiCk Newman
9
Ponadto ze względu na semantykę sposób, w jaki for, intraktuje tablice (tj. Taki sam jak każdy inny obiekt JavaScript), nie jest dopasowany do innych popularnych języków.
// C#char[] a =newchar[]{'A','B','C'};
foreach (char x in a)System.Console.Write(x);//Output: "ABC"// Javachar[] a ={'A','B','C'};for(char x : a)System.out.print(x);//Output: "ABC"// PHP
$a = array('A','B','C');
foreach ($a as $x) echo $x;//Output: "ABC"// JavaScriptvar a =['A','B','C'];for(var x in a) document.write(x);//Output: "012"
TL&DR: Używanie for inpętli w tablicach nie jest złe, w rzeczywistości wręcz przeciwnie.
Myślę, że for inpętla jest klejnotem JS, jeśli jest poprawnie używana w tablicach. Oczekuje się, że będziesz mieć pełną kontrolę nad swoim oprogramowaniem i wiesz, co robisz. Zobaczmy wspomniane wady i obalimy je jeden po drugim.
Pętla przechodzi również przez odziedziczone właściwości: Po pierwsze, wszelkie rozszerzenia Array.prototypepowinny zostać wykonane przy użyciu, Object.defineProperty()a ich enumerabledeskryptor powinien być ustawiony na false. Żadna biblioteka, która tego nie robi, nie powinna być w ogóle używana.
Właściwości, które dodasz do łańcucha dziedziczenia, zostaną później policzone: w przypadku podklasowania tablicy Object.setPrototypeOfwedług klasy lub według klasy extend. Należy ponownie użyć Object.defineProperty(), które domyślnie ustawia writable, enumerablei configurabledeskryptorów do własności false. Zobaczmy tutaj podklasę tablic tutaj ...
functionStack(...a){var stack =newArray(...a);Object.setPrototypeOf(stack,Stack.prototype);return stack;}Stack.prototype =Object.create(Array.prototype);// now stack has full access to array methods.Object.defineProperty(Stack.prototype,"constructor",{value:Stack});// now Stack is a proper constructorObject.defineProperty(Stack.prototype,"peak",{value:function(){// add Stack "only" methods to the Stack.prototype.returnthis[this.length-1];}});var s =newStack(1,2,3,4,1);
console.log(s.peak());
s[s.length]=7;
console.log("length:",s.length);
s.push(42);
console.log(JSON.stringify(s));
console.log("length:",s.length);for(var i in s) console.log(s[i]);
Widzisz więc ... for inpętla jest teraz bezpieczna, ponieważ dbałeś o swój kod.
for inPętla jest powolna: Piekło nie. Jest to zdecydowanie najszybsza metoda iteracji, jeśli zapętlasz rzadkie tablice, które są potrzebne od czasu do czasu. Jest to jedna z najważniejszych sztuczek związanych z wydajnością, którą należy znać. Zobaczmy przykład. Zapętlimy rzadką tablicę.
var a =[];
a[0]="zero";
a[10000000]="ten million";
console.time("for loop on array a:");for(var i=0; i < a.length; i++) a[i]&& console.log(a[i]);
console.timeEnd("for loop on array a:");
console.time("for in loop on array a:");for(var i in a) a[i]&& console.log(a[i]);
console.timeEnd("for in loop on array a:");
@Ravi Shanker Reddy Dobra konfiguracja testu porównawczego. Jak wspomniałem w mojej odpowiedzi, for inpętla przyćmiewa pozostałe „jeśli” tablica jest rzadka, a tym bardziej, jeśli robi się większa. Więc przestawiłem test laboratoryjny dla rzadkiej tablicy, arro wielkości ~ 10000, z tylko 50 pozycjami losowo wybranymi spośród [42,"test",{t:1},null, void 0]losowych indeksów. Od razu zauważysz różnicę. - >> Sprawdź tutaj << - .
Redu,
8
Oprócz innych problemów składnia „for..in” jest prawdopodobnie wolniejsza, ponieważ indeks jest łańcuchem, a nie liczbą całkowitą.
var a =["a"]for(var i in a)
alert(typeof i)// 'string'for(var i =0; i < a.length; i++)
alert(typeof i)// 'number'
Prawdopodobnie nie ma to większego znaczenia. Elementy tablicy są właściwościami obiektu opartego na macierzy lub podobnego do macierzy, a wszystkie właściwości obiektu mają klucze łańcuchowe. O ile silnik JS w jakiś sposób go nie zoptymalizuje, nawet jeśli użyjesz liczby, w wyniku wyszukiwania zostanie przekształcony w ciąg znaków.
cHao
Bez względu na jakiekolwiek problemy z wydajnością, jeśli var i in adopiero zaczynasz korzystać z JavaScript, skorzystaj z indeksu i oczekuj, że indeks będzie liczbą całkowitą, a następnie zrobienie czegoś podobnego a[i+offset] = <value>spowoduje umieszczenie wartości w całkowicie niewłaściwych miejscach. („1” + 1 == „11”).
szmoore
8
Ważnym aspektem jest to, że for...initeruje tylko właściwości zawarte w obiekcie, dla którego ich atrybut właściwości wymiennych jest ustawiony na true. Jeśli więc spróbujemy wykonać iterację nad obiektem, wówczas dowolne właściwości mogą zostać pominięte, jeśli ich atrybut właściwości wyliczalnych ma wartość false. Jest całkiem możliwa zmiana atrybutu właściwości wyliczalnych dla normalnych obiektów Array, aby niektóre elementy nie były wyliczane. Chociaż ogólnie atrybuty właściwości mają zwykle zastosowanie do właściwości funkcji w obiekcie.for...in
Można sprawdzić wartość wyliczalnego atrybutu właściwości przez:
myobject.propertyIsEnumerable('myproperty')
Lub uzyskać wszystkie cztery atrybuty właściwości:
Jest to funkcja dostępna w ECMAScript 5 - we wcześniejszych wersjach nie można było zmienić wartości atrybutu właściwości wyliczalnych (zawsze była ustawiona na true).
for/ inWspółpracuje z dwoma rodzajami zmiennych hashtables (asocjacyjnych) i matrycy (nie asocjacyjną).
JavaScript automatycznie określi sposób, w jaki przechodzi przez elementy. Jeśli więc wiesz, że twoja tablica naprawdę nie jest asocjacyjna, możesz użyć jej for (var i=0; i<=arrayLen; i++)i pominąć iterację automatycznego wykrywania.
Ale moim zdaniem lepiej jest użyć for/ in, proces wymagany do automatycznego wykrywania jest bardzo mały.
Prawdziwa odpowiedź na to zależy od tego, jak przeglądarka analizuje / interpretuje kod JavaScript. Może zmieniać się między przeglądarkami.
Nie mogę wymyślić innych celów, aby nie używać for/ in;
//Non-associativevar arr =['a','b','c'];for(var i in arr)
alert(arr[i]);//Associativevar arr ={
item1 :'a',
item2 :'b',
item3 :'c'};for(var i in arr)
alert(arr[i]);
Niewystarczająco - dodawanie dowolnych nazwanych właściwości do instancji tablic jest w porządku, a te będą testować na truepodstawie hasOwnProperty()kontroli.
Pointy
Dobra uwaga, dzięki. Nigdy sam nie byłem na tyle głupi, aby zrobić to z tablicą, więc nie zastanawiałem się nad tym!
JAL,
1
@Pointy Nie testowałem tego, ale być może można to obejść, isNaNsprawdzając nazwę każdej właściwości.
WynandB
1
@Wynand ciekawy pomysł; jednak tak naprawdę nie rozumiem, dlaczego warto kłopotać się, gdy iteracja z prostym indeksem numerycznym jest tak łatwa.
Pointy
@WynandB przepraszam za guz, ale czuję, że poprawka jest w porządku: isNaNsłuży do sprawdzania, czy zmienna jest wartością specjalną NaN, czy nie, nie można jej używać do sprawdzania „rzeczy innych niż liczby” (możesz użyć zwykłego typeof do tego).
doldt
6
To nie jest koniecznie złe (w oparciu o to, co robisz), ale w przypadku tablic, jeśli coś zostało dodane do Array.prototype, następnie masz zamiar dostać dziwne wyniki. Gdzie można oczekiwać, że ta pętla uruchomi się trzy razy:
var arr =['a','b','c'];for(var key in arr){...}
Jeśli funkcja o nazwie helpfulUtilityMethodzostał dodany do Array„s prototype, wówczas pętla zakończy się działa cztery razy: keybyłoby 0, 1, 2, i helpfulUtilityMethod. Jeśli spodziewałeś się tylko liczb całkowitych, ups.
Tylko uwaga na temat SO - nie ma „powyżej”, ponieważ komentarze cały czas zmieniają kolejność na stronie. Tak naprawdę nie wiemy, jaki masz na myśli komentarz. Z tego powodu dobrze jest powiedzieć „w komentarzu x osoby”.
JAL
@JAL ... lub dodaj bezpośredni link do odpowiedzi.
WynandB
5
Używanie for...inpętli do tablicy nie jest złe, chociaż mogę zgadnąć, dlaczego ktoś ci to powiedział:
1.) Istnieje już funkcja wyższego rzędu lub metoda, która ma ten cel dla tablicy, ale ma większą funkcjonalność i krótszą składnię, zwaną „forEach”: Array.prototype.forEach(function(element, index, array) {} );
2.) Tablice zawsze mieć długość, ale for...ini forEachnie realizują funkcję dla dowolnej wartości, która jest 'undefined'jedynie dla indeksów, które mają określoną wartość. Jeśli więc przypiszesz tylko jedną wartość, te pętle wykonają funkcję tylko raz, ale ponieważ tablica jest wyliczona, zawsze będzie miała długość do najwyższego indeksu, który ma zdefiniowaną wartość, ale ta długość może pozostać niezauważona podczas korzystania z nich pętle
3.) Standard dla pętli wykona funkcję tyle razy, ile zdefiniujesz w parametrach, a ponieważ tablica jest ponumerowana, bardziej sensowne jest określenie, ile razy chcesz wykonać funkcję. W przeciwieństwie do innych pętli, pętla for może następnie wykonać funkcję dla każdego indeksu w tablicy, niezależnie od tego, czy wartość jest zdefiniowana, czy nie.
Zasadniczo możesz użyć dowolnej pętli, ale pamiętaj dokładnie, jak działają. Zrozum warunki, w których powtarzają się różne pętle, ich oddzielne funkcje i zdaj sobie sprawę, że będą one mniej lub bardziej odpowiednie dla różnych scenariuszy.
Można również uznać za lepszą praktykę stosowanie tej forEachmetody niż for...inogólnie pętli, ponieważ łatwiej jest pisać i ma więcej funkcji, więc możesz przyzwyczaić się do używania tej metody i standardu, ale połączenie.
Zobacz poniżej, że dwie pierwsze pętle wykonują instrukcje console.log tylko raz, podczas gdy standardowa pętla wykonuje tę funkcję tyle razy, ile określono, w tym przypadku array.length = 6.
var arr =[];
arr[5]='F';for(var index in arr){
console.log(index);
console.log(arr[index]);
console.log(arr)}// 5// 'F'// => (6) [undefined x 5, 6]
arr.forEach(function(element, index, arr){
console.log(index);
console.log(element);
console.log(arr);});// 5// 'F'// => Array (6) [undefined x 5, 6]for(var index =0; index < arr.length; index++){
console.log(index);
console.log(arr[index]);
console.log(arr);};// 0// undefined// => Array (6) [undefined x 5, 6]// 1// undefined// => Array (6) [undefined x 5, 6]// 2// undefined// => Array (6) [undefined x 5, 6]// 3// undefined// => Array (6) [undefined x 5, 6]// 4// undefined// => Array (6) [undefined x 5, 6]// 5// 'F'// => Array (6) [undefined x 5, 6]
Oto powody, dla których jest to (zwykle) zła praktyka:
for...inpętle iterują wszystkie swoje własne wyliczalne właściwości i wyliczalne właściwości ich prototypu (ów). Zwykle w iteracji tablicy chcemy iterować tylko nad samą tablicą. I nawet jeśli sam nie możesz niczego dodać do tablicy, twoje biblioteki lub framework mogą coś dodać.
Przykład :
Array.prototype.hithere ='hithere';var array =[1,2,3];for(let el in array){// the hithere property will also be iterated over
console.log(el);}
for...inPętle nie gwarantują określonej kolejności iteracji . Chociaż w dzisiejszych czasach większość przeglądarek jest zwykle widoczna, wciąż nie ma 100% gwarancji.
for...inPętle ignorują undefinedelementy tablicy, tj. elementy tablicy, które nie zostały jeszcze przypisane.
Przykład :
const arr =[];
arr[3]='foo';// resize the array to 4
arr[4]=undefined;// add another element with value undefined to it// iterate over the array, a for loop does show the undefined elementsfor(let i =0; i < arr.length; i++){
console.log(arr[i]);}
console.log('\n');// for in does ignore the undefined elementsfor(let el in arr){
console.log(arr[el]);}
for ... in jest przydatny podczas pracy nad obiektem w JavaScript, ale nie dla tablicy, ale nadal nie możemy powiedzieć, że jest to zły sposób, ale nie jest to zalecane, spójrz na poniższy przykład za pomocą for ... in loop:
let txt ="";const person ={fname:"Alireza", lname:"Dezfoolian", age:35};for(const x in person){
txt += person[x]+" ";}
console.log(txt);//Alireza Dezfoolian 35
OK, zróbmy to teraz z Array :
let txt ="";const person =["Alireza","Dezfoolian",35];for(const x in person){
txt += person[x]+" ";}
console.log(txt);//Alireza Dezfoolian 35
Jak widzisz wynik ten sam ...
Ale spróbujmy czegoś, prototypujmy coś do Array ...
Array.prototype.someoneelse ="someoneelse";
Teraz tworzymy nową Array ();
let txt ="";const arr =newArray();
arr[0]='Alireza';
arr[1]='Dezfoolian';
arr[2]=35;for(x in arr){
txt += arr[x]+" ";}
console.log(txt);//Alireza Dezfoolian 35 someoneelse
Widzisz someoneelse !!! ... W tym przypadku przeglądamy nowy obiekt Array!
Więc to jest jeden z powodów, dlaczego musimy użyć for..in starannie, ale nie zawsze jest to przypadek ...
Ponieważ elementy JavaScript są zapisywane jako standardowe właściwości obiektu, nie zaleca się iteracji przez tablice JavaScript przy użyciu for ... w pętlach, ponieważ zostaną wyświetlone normalne elementy i wszystkie wyliczalne właściwości.
chociaż nie zostało to szczegółowo omówione w tym pytaniu, dodam, że istnieje bardzo dobry powód, aby nigdy nie używać ... w połączeniu z NodeList(jak można uzyskać z querySelectorAllwywołania, ponieważ w ogóle nie widzi zwróconych elementów) iteracja tylko nad właściwościami NodeList.
var i = hCol1.length; for (i;i;i--;) {}
pamięci podręcznej i, ponieważ będzie to miało znaczenie i uprości test. - im starsza przeglądarka, tym większa różnica międzyfor
iwhile
ZAWSZE buforuje licznik „i” - i oczywiście negatywne nie zawsze pasuje do sytuacji, a negatywne, podczasobfuscate
gdy kod trochę dla niektórych osób. i zwróć uwagę,var i = 1000; for (i; i; i--) {}
avar b =1000 for (b; b--;) {}
gdzie i idzie od 1000 do 1, a b od 999 do 0. - im starsza przeglądarka, tym bardziej sprzyja wydajności.for(var i = 0, l = myArray.length; i < l; ++i) ...
jest najszybszym i najlepszym, jakie można uzyskać dzięki iteracji do przodu.Odpowiedzi:
Powodem jest to, że jeden konstrukt:
czasami może się zupełnie różnić od innych:
Weź również pod uwagę, że biblioteki JavaScript mogą robić takie rzeczy, co wpłynie na każdą utworzoną tablicę:
źródło
(var x in a)
zamiast(x in a)
- nie chcę tworzyć globalnego.for (var key in object)
. Jeśli jednak chcesz iterować elementy tablicy , użyjfor(var i = 0; i < array.length; i += 1)
.Samo
for-in
stwierdzenie nie jest „złą praktyką”, jednak może być niewłaściwie użyte , na przykład do iteracji po tablicach lub obiektach podobnych do tablic.Celem
for-in
instrukcji jest wyliczenie właściwości obiektu. To oświadczenie wejdzie w górę w łańcuchu prototypów, wyliczając również odziedziczone właściwości, co czasami nie jest pożądane.Ponadto specyfikacja nie gwarantuje kolejności iteracji, co oznacza, że jeśli chcesz „iterować” obiekt tablicowy, dzięki tej instrukcji nie możesz być pewien, że właściwości (indeksy tablicowe) będą odwiedzane w kolejności numerycznej.
Na przykład w JScript (IE <= 8) kolejność wyliczania nawet w obiektach Array jest definiowana w miarę tworzenia właściwości:
Mówiąc również o odziedziczonych właściwościach, jeśli na przykład rozszerzysz
Array.prototype
obiekt (jak niektóre biblioteki, jak robią to MooTools), właściwości te zostaną również wyliczone:Jak powiedziałem wcześniej, aby iterować po tablicach lub obiektach podobnych do tablic, najlepszą rzeczą jest użycie pętli sekwencyjnej , takiej jak zwykła
for
/while
pętla.Jeśli chcesz wyliczyć tylko własne właściwości obiektu (te, które nie są dziedziczone), możesz użyć
hasOwnProperty
metody:Niektórzy nawet zalecają bezpośrednie wywołanie metody,
Object.prototype
aby uniknąć problemów, jeśli ktoś doda właściwość o nazwiehasOwnProperty
do naszego obiektu:źródło
for..in
jest znacznie wolniejsza niż „normalne” pętle.for..in
nie jest to zła praktyka, ale może być nadużywana. Czy masz przykład dobrej praktyki z prawdziwego świata, w którym naprawdę chciałeś przejrzeć wszystkie właściwości obiektów, w tym właściwości odziedziczone?for (var p in array) { array[p]; }
Istnieją trzy powody, dla których nie powinieneś
for..in
iterować elementów tablicy:for..in
zapętli wszystkie własne i odziedziczone właściwości obiektu tablicy, które nie sąDontEnum
; oznacza to, że jeśli ktoś doda właściwości do konkretnego obiektu tablicy (istnieją uzasadnione powody - sam to zrobiłem) lub zmieniłemArray.prototype
(co jest uważane za złą praktykę w kodzie, który powinien działać dobrze z innymi skryptami), właściwości te będą powtarzać się również; odziedziczone właściwości można wykluczyć poprzez sprawdzeniehasOwnProperty()
, ale to nie pomoże ci z właściwościami ustawionymi w samym obiekcie tablicyfor..in
nie gwarantuje się zachowania kolejności elementówjest powolny, ponieważ musisz przejść wszystkie właściwości obiektu tablicy i całego jego łańcucha prototypów i nadal otrzyma tylko nazwę właściwości, tj. aby uzyskać wartość, konieczne będzie dodatkowe wyszukiwanie
źródło
Ponieważ dla ... w wylicza przez obiekt, który zawiera tablicę, a nie samą tablicę. Jeśli dodam funkcję do łańcucha prototypów tablic, zostanie to również uwzględnione. To znaczy
To napisze:
A ponieważ nigdy nie możesz być pewien, że nic nie zostanie dodane do łańcucha prototypów, użyj pętli for, aby wyliczyć tablicę:
To napisze:
źródło
W izolacji nie ma nic złego w korzystaniu z for-in na tablicach. I-in iteruje nazwy właściwości obiektu, aw przypadku tablicy „out-of-the-box” właściwości odpowiadają indeksom tablic. (Wbudowany propertes podobnych
length
,toString
a więc nie są wliczone w iteracji).Jeśli jednak Twój kod (lub używana struktura) doda niestandardowe właściwości do tablic lub do prototypu tablicy, właściwości te zostaną uwzględnione w iteracji, co prawdopodobnie nie jest tym, czego chcesz.
Niektóre frameworki JS, takie jak Prototype, modyfikują prototyp Array. Inne frameworki, takie jak JQuery, nie mają, więc z JQuery można bezpiecznie używać dla.
Jeśli masz wątpliwości, prawdopodobnie nie powinieneś używać for-in.
Alternatywnym sposobem iteracji po tablicy jest użycie pętli for:
Ma to jednak inny problem. Problem polega na tym, że tablica JavaScript może mieć „dziury”. Jeśli zdefiniujesz
arr
jako:Następnie tablica ma dwa elementy, ale długość 101. Użycie for-in da dwa indeksy, podczas gdy pętla for da 101 indeksów, gdzie 99 ma wartość
undefined
.źródło
Od 2016 roku (ES6) możemy używać
for…of
do iteracji tablic, jak zauważył już John Slegers.Chciałbym tylko dodać ten prosty kod demonstracyjny, aby wszystko było bardziej zrozumiałe:
Konsola pokazuje:
Innymi słowy:
for...of
liczy od 0 do 5, a także ignorujeArray.prototype.foo
. Pokazuje wartości tablic .for...in
wyświetla tylko5
, ignorując niezdefiniowane indeksy tablic, ale dodajefoo
. Pokazuje nazwy właściwości tablicy .źródło
Krótka odpowiedź: Po prostu nie warto.
Dłuższa odpowiedź: po prostu nie jest tego warte, nawet jeśli kolejność elementów sekwencyjnych i optymalna wydajność nie są wymagane.
Długa odpowiedź: po prostu nie warto ...
for (var property in array)
spowodujearray
iterację jako obiekt , przemieszczenie łańcucha prototypów obiektu i ostatecznie działanie wolniejsze niżfor
pętla oparta na indeksie .for (... in ...)
nie gwarantuje się zwrócenia właściwości obiektu w kolejności sekwencyjnej, jak można się spodziewać.hasOwnProperty()
i!isNaN()
sprawdzanie do filtrowania właściwości obiektu jest dodatkowym narzutem, który powoduje, że działa jeszcze wolniej i neguje kluczowy powód używania go w pierwszej kolejności, tj. Z powodu bardziej zwięzłego formatu.Z tych powodów akceptowalny kompromis między wydajnością a wygodą nawet nie istnieje. Naprawdę nie ma korzyści, chyba że celem jest obsługa tablicy jako obiektu i wykonywanie operacji na właściwościach obiektu tablicy.
źródło
Oprócz powodów podanych w innych odpowiedziach, możesz nie chcieć używać struktury „for ... in”, jeśli musisz wykonać matematykę ze zmienną licznika, ponieważ pętla iteruje nazwy właściwości obiektu, a więc zmienna jest ciągiem.
Na przykład,
napisze
natomiast,
napisze
Oczywiście można to łatwo obejść przez włączenie
w pętli, ale pierwsza struktura jest bardziej bezpośrednia.
źródło
+
zamiast,parseInt
chyba że naprawdę potrzebujesz liczby całkowitej lub zignoruj nieprawidłowe znaki.parseInt()
nie jest również zalecane. SpróbujparseInt("025");
i to będzie zawieść.parseInt
. Problem polega na tym, że jeśli nie dodasz podstawki, starsze przeglądarki mogą próbować zinterpretować liczbę (w ten sposób 025 staje się ósemkowa). Zostało to naprawione w ECMAScript 5, ale nadal występuje w przypadku liczb rozpoczynających się od „0x” (interpretuje liczbę jako szesnastkową). Aby być po bezpiecznej stronie, użyj podstawy, aby określić liczbę w ten sposóbparseInt("025", 10)
- która określa podstawę 10.Oprócz faktu, że
for
...in
zapętla wszystkie właściwości policzalne (co nie jest tym samym co „wszystkie elementy tablicy”!), Patrz http://www.ecma-international.org/publications/files/ECMA-ST/Ecma -262.pdf , sekcja 12.6.4 (wydanie piąte) lub 13.7.5.15 (wydanie siódme):(Podkreśl moje.)
Oznacza to, że jeśli przeglądarka tego chce, może przeglądać właściwości w kolejności, w jakiej zostały wstawione. Lub w kolejności numerycznej. Lub w porządku leksykalnym (gdzie „30” występuje przed „4”! Pamiętaj, że wszystkie klucze obiektów - a zatem wszystkie indeksy tablic - są w rzeczywistości łańcuchami, więc to ma sens). Mógłby je przeglądać za pomocą segmentu, jeśli zaimplementował obiekty jako tabele skrótów. Lub weź dowolny z nich i dodaj „wstecz”. Przeglądarka może nawet iterować losowo i być zgodna z ECMA-262, o ile odwiedza każdą właściwość dokładnie raz.
W praktyce większość przeglądarek lubi iterować mniej więcej w tej samej kolejności. Ale nic nie mówi, że muszą. Jest to specyficzne dla implementacji i może ulec zmianie w dowolnym momencie, jeśli okaże się, że inny sposób jest znacznie bardziej wydajny.
Tak czy inaczej
for
...in
niesie ze sobą żadnego związku z porządkiem. Jeśli zależy Ci na porządku, wypowiedz się o nim i użyj zwykłejfor
pętli z indeksem.źródło
Głównie dwa powody:
Jeden
Jak powiedzieli inni, możesz dostać klucze, które nie są w twojej tablicy lub są dziedziczone z prototypu. Więc jeśli, powiedzmy, biblioteka dodaje właściwość do prototypów Array lub Object:
Otrzymasz to jako część każdej tablicy:
możesz to rozwiązać za pomocą metody hasOwnProperty:
ale dotyczy to iteracji po dowolnym obiekcie z pętlą for-in.
Dwa
Zwykle kolejność elementów w tablicy jest ważna, ale pętla for-in niekoniecznie iteruje we właściwej kolejności, ponieważ traktuje tablicę jako obiekt, tak jak jest implementowana w JS, a nie jako tablica. Wydaje się, że to drobiazg, ale naprawdę może zepsuć aplikacje i jest trudny do debugowania.
źródło
Object.keys(a).forEach( function(item) { console.log(item) } )
iteruje tablicę własnych kluczy własności, a nie tych odziedziczonych po prototypie.array.forEach
, wstawiając określony kod do swoich skryptów. Zobacz Polyfill developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Ponieważ wylicza poprzez pola obiektowe, a nie indeksy. Możesz uzyskać wartość z indeksem „długość” i wątpię, czy tego chcesz.
źródło
Nie sądzę, że mam wiele do dodania np. W niektórych przypadkach należy unikać odpowiedzi tryptyku lub odpowiedzi CMS na pytanie, dlaczego
for...in
należy używać.Chciałbym jednak dodać, że we współczesnych przeglądarkach istnieje alternatywa, z
for...in
której można korzystać w przypadkach, gdyfor...in
nie można jej użyć. Ta alternatywa tofor...of
:Uwaga :
Niestety żadna wersja programu Internet Explorer nie obsługuje
for...of
( Edge 12+ ), więc musisz poczekać trochę dłużej, aż będziesz mógł użyć go w kodzie produkcyjnym po stronie klienta. Jednak użycie kodu JS po stronie serwera powinno być bezpieczne (jeśli używasz Node.js ).źródło
for-of
niefor-in
, prawda?Problem z
for ... in ...
- a staje się to problemem tylko wtedy, gdy programista tak naprawdę nie rozumie języka; tak naprawdę nie jest to błąd ani nic takiego - polega na tym, że iteruje wszystkie elementy obiektu (cóż, wszystkie elementy policzalne , ale na razie jest to szczegół). Jeśli chcesz iterować tylko indeksowane właściwości tablicy, jedynym gwarantowanym sposobem na zachowanie spójności semantycznej jest użycie indeksu liczb całkowitych (to znaczyfor (var i = 0; i < array.length; ++i)
pętli stylów).Każdy obiekt może mieć dowolne właściwości z nim związane. W szczególności nie byłoby nic strasznego w ładowaniu dodatkowych właściwości do instancji tablicy. Kod, który chce widzieć tylko indeksowane właściwości podobne do tablic, musi zatem trzymać się indeksu liczb całkowitych. Kod, który jest w pełni świadomy tego, co
for ... in
robi i naprawdę musi zobaczyć wszystkie właściwości, to też w porządku.źródło
for in
w porównaniu do zwykłej pętli for tablice te zostałyby iterowane? (co w gruncie rzeczy byłoby wolne, prawda?)in
wfor ... in
pętli, po prostufor ... in
na tablicach; istnieje wiele dobrych powodów, aby tego nie robić. To nie tyle problem z wydajnością, co problem „upewnij się, że się nie złamie”.[{a:'hey',b:'hi'},{a:'hey',b:'hi'}]
:, ale tak, rozumiem.Ponadto ze względu na semantykę sposób, w jaki
for, in
traktuje tablice (tj. Taki sam jak każdy inny obiekt JavaScript), nie jest dopasowany do innych popularnych języków.źródło
TL&DR: Używanie
for in
pętli w tablicach nie jest złe, w rzeczywistości wręcz przeciwnie.Myślę, że
for in
pętla jest klejnotem JS, jeśli jest poprawnie używana w tablicach. Oczekuje się, że będziesz mieć pełną kontrolę nad swoim oprogramowaniem i wiesz, co robisz. Zobaczmy wspomniane wady i obalimy je jeden po drugim.Array.prototype
powinny zostać wykonane przy użyciu,Object.defineProperty()
a ichenumerable
deskryptor powinien być ustawiony nafalse
. Żadna biblioteka, która tego nie robi, nie powinna być w ogóle używana.Object.setPrototypeOf
według klasy lub według klasyextend
. Należy ponownie użyćObject.defineProperty()
, które domyślnie ustawiawritable
,enumerable
iconfigurable
deskryptorów do własnościfalse
. Zobaczmy tutaj podklasę tablic tutaj ...Widzisz więc ...
for in
pętla jest teraz bezpieczna, ponieważ dbałeś o swój kod.for in
Pętla jest powolna: Piekło nie. Jest to zdecydowanie najszybsza metoda iteracji, jeśli zapętlasz rzadkie tablice, które są potrzebne od czasu do czasu. Jest to jedna z najważniejszych sztuczek związanych z wydajnością, którą należy znać. Zobaczmy przykład. Zapętlimy rzadką tablicę.źródło
for in
pętla przyćmiewa pozostałe „jeśli” tablica jest rzadka, a tym bardziej, jeśli robi się większa. Więc przestawiłem test laboratoryjny dla rzadkiej tablicy,arr
o wielkości ~ 10000, z tylko 50 pozycjami losowo wybranymi spośród[42,"test",{t:1},null, void 0]
losowych indeksów. Od razu zauważysz różnicę. - >> Sprawdź tutaj << - .Oprócz innych problemów składnia „for..in” jest prawdopodobnie wolniejsza, ponieważ indeks jest łańcuchem, a nie liczbą całkowitą.
źródło
var i in a
dopiero zaczynasz korzystać z JavaScript, skorzystaj z indeksu i oczekuj, że indeks będzie liczbą całkowitą, a następnie zrobienie czegoś podobnegoa[i+offset] = <value>
spowoduje umieszczenie wartości w całkowicie niewłaściwych miejscach. („1” + 1 == „11”).Ważnym aspektem jest to, że
for...in
iteruje tylko właściwości zawarte w obiekcie, dla którego ich atrybut właściwości wymiennych jest ustawiony na true. Jeśli więc spróbujemy wykonać iterację nad obiektem, wówczas dowolne właściwości mogą zostać pominięte, jeśli ich atrybut właściwości wyliczalnych ma wartość false. Jest całkiem możliwa zmiana atrybutu właściwości wyliczalnych dla normalnych obiektów Array, aby niektóre elementy nie były wyliczane. Chociaż ogólnie atrybuty właściwości mają zwykle zastosowanie do właściwości funkcji w obiekcie.for...in
Można sprawdzić wartość wyliczalnego atrybutu właściwości przez:
Lub uzyskać wszystkie cztery atrybuty właściwości:
Jest to funkcja dostępna w ECMAScript 5 - we wcześniejszych wersjach nie można było zmienić wartości atrybutu właściwości wyliczalnych (zawsze była ustawiona na true).
źródło
for
/in
Współpracuje z dwoma rodzajami zmiennych hashtables (asocjacyjnych) i matrycy (nie asocjacyjną).JavaScript automatycznie określi sposób, w jaki przechodzi przez elementy. Jeśli więc wiesz, że twoja tablica naprawdę nie jest asocjacyjna, możesz użyć jej
for (var i=0; i<=arrayLen; i++)
i pominąć iterację automatycznego wykrywania.Ale moim zdaniem lepiej jest użyć
for
/in
, proces wymagany do automatycznego wykrywania jest bardzo mały.Prawdziwa odpowiedź na to zależy od tego, jak przeglądarka analizuje / interpretuje kod JavaScript. Może zmieniać się między przeglądarkami.
Nie mogę wymyślić innych celów, aby nie używać
for
/in
;źródło
Array
jestObject
teżfor ... in
współpracuje z obiektami. Nie ma czegoś takiego jak automatyczne wykrywanie.Ponieważ będzie to powtarzać właściwości należące do obiektów w łańcuchu prototypów, jeśli nie będziesz ostrożny.
Możesz użyć
for.. in
, po prostu sprawdź każdą właściwość hasOwnProperty .źródło
true
podstawiehasOwnProperty()
kontroli.isNaN
sprawdzając nazwę każdej właściwości.isNaN
służy do sprawdzania, czy zmienna jest wartością specjalną NaN, czy nie, nie można jej używać do sprawdzania „rzeczy innych niż liczby” (możesz użyć zwykłego typeof do tego).To nie jest koniecznie złe (w oparciu o to, co robisz), ale w przypadku tablic, jeśli coś zostało dodane do
Array.prototype
, następnie masz zamiar dostać dziwne wyniki. Gdzie można oczekiwać, że ta pętla uruchomi się trzy razy:Jeśli funkcja o nazwie
helpfulUtilityMethod
został dodany doArray
„sprototype
, wówczas pętla zakończy się działa cztery razy:key
byłoby0
,1
,2
, ihelpfulUtilityMethod
. Jeśli spodziewałeś się tylko liczb całkowitych, ups.źródło
Należy używać
for(var x in y)
tylko na listach właściwości, a nie na obiektach (jak wyjaśniono powyżej).źródło
Używanie
for...in
pętli do tablicy nie jest złe, chociaż mogę zgadnąć, dlaczego ktoś ci to powiedział:1.) Istnieje już funkcja wyższego rzędu lub metoda, która ma ten cel dla tablicy, ale ma większą funkcjonalność i krótszą składnię, zwaną „forEach”:
Array.prototype.forEach(function(element, index, array) {} );
2.) Tablice zawsze mieć długość, ale
for...in
iforEach
nie realizują funkcję dla dowolnej wartości, która jest'undefined'
jedynie dla indeksów, które mają określoną wartość. Jeśli więc przypiszesz tylko jedną wartość, te pętle wykonają funkcję tylko raz, ale ponieważ tablica jest wyliczona, zawsze będzie miała długość do najwyższego indeksu, który ma zdefiniowaną wartość, ale ta długość może pozostać niezauważona podczas korzystania z nich pętle3.) Standard dla pętli wykona funkcję tyle razy, ile zdefiniujesz w parametrach, a ponieważ tablica jest ponumerowana, bardziej sensowne jest określenie, ile razy chcesz wykonać funkcję. W przeciwieństwie do innych pętli, pętla for może następnie wykonać funkcję dla każdego indeksu w tablicy, niezależnie od tego, czy wartość jest zdefiniowana, czy nie.
Zasadniczo możesz użyć dowolnej pętli, ale pamiętaj dokładnie, jak działają. Zrozum warunki, w których powtarzają się różne pętle, ich oddzielne funkcje i zdaj sobie sprawę, że będą one mniej lub bardziej odpowiednie dla różnych scenariuszy.
Można również uznać za lepszą praktykę stosowanie tej
forEach
metody niżfor...in
ogólnie pętli, ponieważ łatwiej jest pisać i ma więcej funkcji, więc możesz przyzwyczaić się do używania tej metody i standardu, ale połączenie.Zobacz poniżej, że dwie pierwsze pętle wykonują instrukcje console.log tylko raz, podczas gdy standardowa pętla wykonuje tę funkcję tyle razy, ile określono, w tym przypadku array.length = 6.
źródło
Oto powody, dla których jest to (zwykle) zła praktyka:
for...in
pętle iterują wszystkie swoje własne wyliczalne właściwości i wyliczalne właściwości ich prototypu (ów). Zwykle w iteracji tablicy chcemy iterować tylko nad samą tablicą. I nawet jeśli sam nie możesz niczego dodać do tablicy, twoje biblioteki lub framework mogą coś dodać.Przykład :
for...in
Pętle nie gwarantują określonej kolejności iteracji . Chociaż w dzisiejszych czasach większość przeglądarek jest zwykle widoczna, wciąż nie ma 100% gwarancji.for...in
Pętle ignorująundefined
elementy tablicy, tj. elementy tablicy, które nie zostały jeszcze przypisane.Przykład :
źródło
for ... in jest przydatny podczas pracy nad obiektem w JavaScript, ale nie dla tablicy, ale nadal nie możemy powiedzieć, że jest to zły sposób, ale nie jest to zalecane, spójrz na poniższy przykład za pomocą for ... in loop:
OK, zróbmy to teraz z Array :
Jak widzisz wynik ten sam ...
Ale spróbujmy czegoś, prototypujmy coś do Array ...
Teraz tworzymy nową Array ();
Widzisz someoneelse !!! ... W tym przypadku przeglądamy nowy obiekt Array!
Więc to jest jeden z powodów, dlaczego musimy użyć for..in starannie, ale nie zawsze jest to przypadek ...
źródło
Pętla for ... in zawsze wylicza klucze. Klucze właściwości obiektów są zawsze ciągiem, nawet indeksowane właściwości tablicy:
źródło
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections
źródło
chociaż nie zostało to szczegółowo omówione w tym pytaniu, dodam, że istnieje bardzo dobry powód, aby nigdy nie używać ... w połączeniu z
NodeList
(jak można uzyskać zquerySelectorAll
wywołania, ponieważ w ogóle nie widzi zwróconych elementów) iteracja tylko nad właściwościami NodeList.w przypadku pojedynczego wyniku otrzymałem:
co wyjaśniało, dlaczego mój
for (node in nodes) node.href = newLink;
zawodził.źródło