@Coldpeer:
@Zi00mal:
Uściślijmy przechodzenie po obiektach/tablicach w JavaScripcie. Funkcji .forEach() i pętli for..in nie wolno -- a czasem się wręcz nie da -- stosować zamiennie.
Tablice to specjalne obiekty, które przechowują swoje elementy pod kluczami będącymi kolejnymi indeksami od 0 do tablica.length - 1. Np. tablica złożona z trzech stringów i jednej liczby: ["ala", "ma", "kota", 123]. Ogólnie, w JavaScripcie, tablice mogą mieć też klucze inne niż indeksy, ale nie w JSON-ie.
Obiekty można nazwać od biedy czymś w rodzaju hashmap lub tablic asocjacyjnych z PHP. Obiekty mapują klucze (będące ciągami znaków) na wartości, np. { response: "Jakiś tekst", error: 123 } (JSON wymaga, by klucze zawsze były otoczone cudzysłowami, ale w JS-ie zwykle można je pominąć).
I teraz: tablice mają metodę .forEach(), o której wspomniał @Coldpeer . To poprawna metoda iteracji po tablicy, choć jest niestety wolniejsza od klasycznej pętli for:
Kopiuj
for (var i = 0; i < tablica.length; i++) {
...
}
Szybkość iteracji jednak rzadko ma znaczenie.
Problem w tym, że obiekty nie mają metody .forEach() -- jest ona obecna tylko na tablicach. Więc w przypadku tablic asocjacyjnych z PHP, które są zapewne serializowane jako obiekty JSON, mielibyśmy problem. Przeglądarka powiedziałaby, że data.response.forEach to nie funkcja (tylko undefined).
Obiekty możemy przechodzić pętlą for..in, przy czym zmiennej sterującej nie nazwałbym elem, bo sugeruje to element (wartość elementu), a zmienna sterująca w pętli for to klucz. Nazwałbym ją więc raczej key czy propertyName (skrótowo: prop).
Używając pętli for..in, praktycznie zawsze powinniśmy się zabezpieczyć przed własnościami odziedziczonymi z prototypu Object.prototype. Wszystkie obiekty w JavaScripcie dziedziczą kilka własności standardowych z Object.prototype. Normalnie nie stanowi to problemu, bo własności standardowe mają flagę [[Enumerable]] ustawioną na false, a to oznacza, że nie pokazują się w pętli for..in. Ale jeśli ktoś zrobi nieostrożnie np. tak:
Kopiuj
Object.prototype.cośtam = function() {
// ...
};
to własność cośtam będzie miała [[Enumerable]] ustawione na true i pojawi się w pętli for..in takiej jak ta, którą napisałeś. Bo Twój obiekt data.response odziedziczy własność cośtam po prototypie obiektu, mimo że tego nie chciałeś.
Dlatego w każdej iteracji pętli warto sprawdzić, czy dana właściwość jest tzw. "właściwością własną" (po angielsku lepiej brzmi: own property) danego obiektu (w przeciwnym wypadku wzięła się stąd, że została odziedziczona).
Zabezpieczona pętla wygląda tak:
Kopiuj
var response = data.response; // żeby się nie powtarzać
for (var key in response) {
if (response.hasOwnProperty(key)) {
alert(key + " - " + response[key]);
}
}
Ciekawskim powiem, że i to nie jest stuprocentowe zabezpieczenie, bo wykrzaczy się, jeśli jakiś dowcipniś wstawi nam do response właściwość o kluczu... hasOwnProperty :-). Po stronie klienta nie musimy się tym przejmować, ale dla wielu serwerów z NodeJS-a był to problem, który trzeba było sprytnie obchodzić.