for...in

Wyrażenie for...in iteruje po nazwach wszystkich wyliczalnych własnościach obiektu, włączając w to odziedziczone wyliczalne właściwości. for...in pomija te właściwości, które są indeksowane Symbolami.

Składnia

for (zmienna in obiekt)
  polecenie
zmienna
W każdej iteracji, zmiennej przypisywana jest inna nazwa własności.
obiekt
Obiekt, po którego niesymbolicznych wyliczalnych własnościach iterujemy.

Opis

for...in iteruje jedynie po wyliczalnych i jednocześnie niesymbolicznych właściwościach. Obiekty utworzone za pomocą wbudowanych konstruktorów (np. Array czy Object) dziedziczą niewyliczalne właściwości z m.in. Object.protoype oraz String.prototype, takie jak metoda indexOf() ze String albo toString()Object. Pętla przejdzie przez wszystkie wyliczalne właściwości – zarówno własne, jak i odziedziczone z prototypu konstruktora.

Usunięte, dodane lub zmodyfikowane własności

Pętla for...in iteruje po właściwościach w arbitralnej kolejności (zobacz więcej w opisie operatora delete, dlaczego nie można liczyć na konkretną kolejność właściwości – szczególnie w różnych przeglądarkach).

Jeśli właściwość zostanie zmodyfikowana w danej iteracji, a dopiero następnie odwiedzona przez for...in, przyjmuje tę późniejszą wartość. Usunięcie właściwości przed jej odwiedzeniem przez pętlę, spowoduje, że nie wystąpi w żadnej z późniejszych iteracji. Natomiast właściwość dodana do obiektu w trakcie iterowania może (ale nie musi) zostać odwiedzona przez pętlę.

Ogólnie, w trakcie iterowania z użyciem for...in najlepiej jest nie modyfikować innych właściwości obiektu niż ta, która jest aktualnie odwiedzona. Nie ma żadnej gwarancji, że dodana właściwość zostanie odwiedzona, ani że właściwość usuwana zostanie odwiedzona przed skasowaniem. Podobnie, nie ma gwarancji, czy właściwość zmodyfikowana zostanie odwiedzona przed, czy po modyfikacji.

Iterowanie po tablicy i for...in

Uwaga: wyrażenie for...in nie powinno być używane na obiektach klasyArray, gdzie kolejność elementów jest ważna.

Indeksy tablic są niczym innym jak właściwościami obiektu – z tym, że ich nazwy są liczbowe, a nie słowne. Dlatego nie ma gwarancji, że for...in odwiedzi je w jakiejkolwiek konkretnej kolejności. Ponadto, pętla zwróci także nieliczbowe właściwości oraz te odziedziczone.

Kiedy kolejność odwiedzania elementów ma znaczenie, iterowanie po elementach tablicy powinno odbywać się z użyciem pętli for (albo Array.prototype.forEach() albo pętli for...of), ze względu na to, że kolejność iterowania po właściwościach jest zależna od implementacji.

Iterowanie jedynie po własnych właściwościach

Jeżeli potrzebujesz iterować tylko po własnych właściwościach obiektu, użyj getOwnPropertyNames(), albo sprawdzaj za każdym razem, czy właściwość jest właściwością własną za pomocą hasOwnProperty()(propertyIsEnumerable() również moży zostać użyte). Alternatywnie, jeśli jesteś pewien, że nie spowoduje to problemów w kodzie, możesz rozszerzyć wbudowane prototypy o metodę sprawdzającą, czy właściwość jest własna.

Dlaczego używać for...in?

Skoro pętla for...in została stworzona do iterowania po właściwościach obiektu i nie jest zalecana do pracy z tablicami, to jaki może bć z niej pożytek?

Najbardziej praktyczna jest w sytuacjach związanych z debugowaniem, zapewniając łatwy sposób na sprawdzenie właściwości obiektu (wypisując je do konsoli lub gdziekolwiek indziej). Oprócz tego, są sytuacje, kiedy pary klucz-wartość są indeksowane innym typem niż liczba. Wtedy po takim "słowniku" można przeiterować za pomocą for...in.

Przykłady

Użycie for...in

Pętla for...in poniżej iteruje po wszystkich wyliczalnych właściwościach obiektu obj i wypisuje je do konsoli.

var obj = {a: 1, b: 2, c: 3};
    
for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
}

// Wyjście:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"

Iterowanie po własnych właściwościach

Następny przykład pokazuje użycie hasOwnProperty(), aby nie wyświetlać właściwości odziedziczonych przez ColoredTriangle.

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

function ColoredTriangle() {
  this.color = 'red';
}

ColoredTriangle.prototype = triangle;

var obj = new ColoredTriangle();

for (const prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    console.log(`obj.${prop} = ${obj[prop]}`);
  } 
}

// Wyjście:
// "obj.color = red"

Specyfikacje

Specyfikacja Status Komentarz
ECMAScript (ECMA-262)
The definition of 'for...in statement' in that specification.
Living Standard
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'for...in statement' in that specification.
Standard
ECMAScript 5.1 (ECMA-262)
The definition of 'for...in statement' in that specification.
Standard
ECMAScript 3rd Edition (ECMA-262)
The definition of 'for...in statement' in that specification.
Standard
ECMAScript 1st Edition (ECMA-262)
The definition of 'for...in statement' in that specification.
Standard Definicja początkowa.

Zgodność z przeglądarkami

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
for...inChrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 6Opera Full support 2Safari Full support 1WebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support 10.1Safari iOS Full support 1Samsung Internet Android Full support 1.0nodejs Full support 0.1.100

Legend

Full support  
Full support

Zgodność: Wyrażenie incjalizujące w trybie ścisłym

Przed Firefoksem 40, było możliwe używanie wyrażenia incjalizującego (i=0) w pętli for...in:

var obj = {a: 1, b: 2, c: 3};
for (var i = 0 in obj) {
  console.log(obj[i]);
}
// 1
// 2
// 3

To niestandardowe zachowanie jest ignorowane począwszy od wersji 40 i powoduje zgłoszenie błędu SyntaxError ("for-in loop head declarations may not have initializers") w trybie ścisłym (błąd 748550 i błąd 1164741).

Inne silniki, takie jak v8 (Chrome), Chakra (IE/Edge), i JSC (WebKit/Safari) również mogą przestać obsługiwać taką konstrukcję.

Zobacz też