Pętla JavaScript foreach na obiekcie tablicy asocjacyjnej

184

Dlaczego moja pętla for-each nie iteruje po moim obiekcie tablicy asocjacyjnej JavaScript?

// defining an array
var array = [];

// assigning values to corresponding keys
array["Main"] = "Main page";
array["Guide"] = "Guide page";
array["Articles"] = "Articles page";
array["Forum"] = "Forum board";

// expected: loop over every item,
// yet it logs only "last" assigned value - "Forum"
for (var i = 0; i < array.length; i++) {
    console.log(array[i]);
}

EDYCJA: jQuery each()może być pomocna: https://api.jquery.com/jQuery.each/

Szymon Toda
źródło
1
Tworzysz tablicę, ale następnie używasz jej jako mapy. Wygląda na to, że chcesz zamiast tego zwykły obiekt.
Jon,
4
Nie ma czegoś takiego jak associative arraysw JS: jest to zwykły Array lub Object. Nic nie stoi na przeszkodzie, aby dodać właściwości nienumeryczne Array, ale to nie oznacza associative- w szczególności lengthwłaściwość nie zlicza automatycznie tych właściwości.
raina77ow
3
re: W JS nie ma takich rzeczy jak tablice asocjacyjne. - sformułowane inaczej: JavaScript używa nazwy „Obiekt” zamiast nazwy „tablica asocjacyjna”. Ale nie ma właściwości „.length”.
Jesse Chisholm

Odpowiedzi:

319

.lengthWłaściwość śledzi tylko właściwości z wskaźników liczbowych (elementy). Używasz łańcuchów do kluczy.

Możesz to zrobić:

var arr_jq_TabContents = {}; // no need for an array

arr_jq_TabContents["Main"] = jq_TabContents_Main;
arr_jq_TabContents["Guide"] = jq_TabContents_Guide;
arr_jq_TabContents["Articles"] = jq_TabContents_Articles;
arr_jq_TabContents["Forum"] = jq_TabContents_Forum;

for (var key in arr_jq_TabContents) {
    console.log(arr_jq_TabContents[key]);
}

Aby być bezpiecznym, dobrze jest w takich pętlach upewnić się, że żadna z właściwości nie jest nieoczekiwanym wynikiem dziedziczenia:

for (var key in arr_jq_TabContents) {
  if (arr_jq_TabContents.hasOwnProperty(key))
    console.log(arr_jq_TabContents[key]);
}

edit - prawdopodobnie warto teraz zauważyć, że Object.keys()funkcja jest dostępna w nowoczesnych przeglądarkach oraz w Node itp. Ta funkcja zwraca „własne” klucze obiektu w postaci tablicy:

Object.keys(arr_jq_TabContents).forEach(function(key, index) {
  console.log(this[key]);
}, arr_jq_TabContents);

Przekazana funkcja zwrotna .forEach()jest wywoływana z każdym kluczem i indeksem klucza w tablicy zwracanej przez Object.keys(). Przekazał również tablicę, przez którą iteruje funkcja, ale ta tablica nie jest dla nas zbyt przydatna; potrzebujemy oryginalnego przedmiotu . Można to uzyskać bezpośrednio poprzez nazwę, ale (moim zdaniem) trochę przyjemniej jest przekazać to jawnie, co jest zrobione przez przekazanie drugiego argumentu do .forEach()- oryginalnego obiektu - który będzie powiązany jak thiswewnątrz wywołania zwrotnego. (Właśnie zobaczyłem, że zostało to odnotowane w komentarzu poniżej).

Spiczasty
źródło
Co to jest var arr_jq_TabContents = {};? Mam na myśli {}
Szymon Toda
1
@Ultra jest to pusty literał obiektu. Oznacza to po prostu, że zmienna jest inicjalizowana z odniesieniem do nowego pustego obiektu.
Pointy
@Ultra nie potrzebujesz instancji Array, ponieważ w tym kodzie nie używasz jej jak tablicy JavaScript. JavaScript nie ma „tablic asocjacyjnych”, jak niektóre inne języki.
Pointy,
1
Jaka jest różnica między przypisywaniem []a {}? Tylko różne prototypy?
SoonDead
8
Zamiast używać hasOwnProperty, powinno być możliwe we wszystkich nowoczesnych przeglądarkach internetowych iteracja kluczy obiektu przy użyciu: Object.keys(arr_jq_TabContents).forEach( function(key) { ... } );
Gregory Bell
84

To bardzo proste podejście. Zaletą jest to, że możesz również zdobyć klucze:

for (var key in array) {
    var value = array[key];
    console.log(key, value);
}

W przypadku ES6:

array.forEach(value => {
  console.log(value)
})  

Dla ES6: (jeśli chcesz mieć wartość, indeks i samą tablicę)

array.forEach((value, index, self) => {
  console.log(value, index, self)
})  
tika
źródło
12
Nie używaj varw pętlach sugerujących zasięg, który nie istnieje. Stosować varprzed pętlą lub letw pętli.
ceving
2
@ceving, czy możesz wyjaśnić, dlaczego nie używać var ​​w pętlach? Pochodzę z C ++ / PHP i nie rozumiem tego. określanie zakresu istnieje w pętli, ale jest tymczasowe, więc nie jestem pewien, co masz na myśli.
Dennis,
6
@Dennis W większości języków deklaracja zmiennej w forpętli generuje zakres ograniczony do treści forpętli. Ale w JavaScript zmienna zadeklarowana przez varjest zawsze funkcją globalną, nawet jeśli zapiszesz ją w forpętli. Zobacz tutaj: davidwalsh.name/for-and-against-let
ceving
1
nie wycieki pamięci jako takie, ale zdecydowanie „wycieki pamięci”. varw Javascript tworzy zmienne w pamięci nawet po zakończeniu pętli.
ahnbizcad
Myślę, że celem tych komentarzy dotyczących użycia „var” jest teraz użycie „let” w ogóle, ale w szczególności w pętli. Przyczyny wyjaśniono powyżej, ale podsumowując, wynika to z zakresu, „zmienna” tworzy zasięg globalny.
DeeZone
6

Jest już kilka prostych przykładów, ale po tym, jak sformułowałeś swoje pytanie, zauważyłem, że prawdopodobnie pochodzisz z tła PHP i oczekujesz, że JavaScript będzie działał w ten sam sposób - tak nie jest. PHP arraybardzo różni się od JavaScript Array.

W PHP tablica asocjacyjna może zrobić większość tego, co tablica indeksowana numerycznie ( array_*funkcje działają, możesz to count()zrobić itp.) Po prostu tworzysz tablicę i zaczynasz przypisywać do indeksów łańcuchowych zamiast liczbowych.

W JavaScript wszystko jest obiektem (z wyjątkiem prymitywów: string, numeric, boolean), a tablice to pewna implementacja, która pozwala mieć indeksy numeryczne. Wszystko popychany do tablicy wpłynie ITS length, i można powtórzyć nad zastosowaniem metod Array ( map, forEach, reduce, filter, find, itd.) Jednakże, ponieważ wszystko jest obiektem, zawsze jesteś wolny, aby po prostu właściwości przypisywać, bo to jest coś zrobić, aby dowolny obiekt. Notacja w nawiasach kwadratowych to po prostu inny sposób uzyskania dostępu do właściwości, więc w twoim przypadku:

array['Main'] = 'Main Page';

jest w rzeczywistości równoważne z:

array.Main = 'Main Page';

Z twojego opisu domyślam się, że chcesz mieć „tablicę asocjacyjną”, ale w przypadku JavaScript jest to prosty przypadek użycia obiektu jako tablicy mieszającej. Wiem też, że to przykład, ale unikaj nieistotnych nazw, które opisują tylko typ zmiennej (np. array) I nazwę na podstawie tego, co powinna zawierać (np pages.). Proste obiekty nie mają wielu dobrych bezpośrednich sposobów iteracji, więc często zamieniamy się następnie w tablice, używając najpierw Objectmetod ( Object.keysw tym przypadku - jest to również entriesi valuesjest teraz dodawane do niektórych przeglądarek), które możemy zapętlić.

// assigning values to corresponding keys
const pages = {
  Main: 'Main page',
  Guide: 'Guide page',
  Articles: 'Articles page',
  Forum: 'Forum board',
};

Object.keys(pages).forEach((page) => console.log(page));
Josh z Qaribou
źródło
4

arr_jq_TabContents[key] widzi tablicę jako postać z indeksem 0.

MSO
źródło
4

Oto prosty sposób użycia tablicy asocjacyjnej jako ogólnego typu obiektu:

Object.prototype.forEach = function(cb){
   if(this instanceof Array) return this.forEach(cb);
   let self = this;
   Object.getOwnPropertyNames(this).forEach(
      (k)=>{ cb.call(self, self[k], k); }
   );
};

Object({a:1,b:2,c:3}).forEach((value, key)=>{ 
    console.log(`key/value pair: ${key}/${value}`);
});

Chouettou
źródło
1

W większości przypadków jest to (zasadniczo) nieprawidłowe:

var array = [];
array["Main"] = "Main page";

To tworzy właściwość niebędącą elementem tablicy o nazwie Main. Chociaż tablice są obiektami, zwykle nie chcesz tworzyć na nich właściwości niebędących elementami.

Jeśli chcesz indeksować do arraywedług tych nazw, zwykle używasz Mapzwykłego obiektu lub zwykłego obiektu, a nie tablicy.

Z Map(ES2015 +), do którego zadzwonię, mapponieważ jestem kreatywny:

let map = new Map();
map.set("Main", "Main page");

następnie iteracyjne go za pomocą iteratorów z jego values, keyslub entriesmetodami, na przykład:

for (const value of map.values()) {
    // Here, `value` will be `"Main page"`, etc.
}

Używając zwykłego obiektu, który będę twórczo nazwać obj:

let obj = Object.create(null); // Creates an object with no prototype
obj.Main = "Main page"; // Or: `obj["Main"] = "Main page";`

którą następnie iteracyjne jego zawartość za pomocą Object.keys, Object.values, lub Object.entries, na przykład:

for (const value of Object.values(proches_X)) {
    // Here, `value` will be `"Main page"`, etc.
}
TJ Crowder
źródło
0

var obj = {
  no: ["no", 32],
  nt: ["no", 32],
  nf: ["no", 32, 90]
};

count = -1; // which must be static value
for (i in obj) {
  count++;
  if (obj.hasOwnProperty(i)) {
    console.log(obj[i][count])
  };
};

w tym kodzie użyłem metody nawiasów do wywołania wartości w tablicy, ponieważ zawierała ona tablicę, jednak w skrócie idea, która zmienna i ma klucz własności i pętla nazywana jest obiema wartościami tablicy skojarzonej

metoda idealna, jeśli jesteś zainteresowany, naciśnij lubię

Dev-Wb Ahmed
źródło
Nie rzucasz tablicy w pętlę, tylko przechodzisz przez obiekt, który ma tablice w swoich kluczach. Przeczytaj pytanie i spójrz na przykład.
Pedro Joaquín
0

Możesz to zrobić

var array = [];

// assigning values to corresponding keys
array[0] = "Main page";
array[1] = "Guide page";
array[2] = "Articles page";
array[3] = "Forum board";


array.forEach(value => {
    console.log(value)
})
Shuvro
źródło