Proč při iteraci přes hodnoty vrací typeof(value) „řetězec“, když je hodnota číslo? JavaScript

Pro tento test používám Google Chrome:

Na rozdíl od intuice první smyčka upozorní „řetězec“ třikrát, zatímco druhá smyčka třikrát „číslo“.

numarray = [1, 2, 3];

//for-each loop
for(num in numarray)
    alert(typeof(num));

// Standard loop
for(i=0; i<numarray.length; i++)
    alert(typeof(numarray[i]));

Čekal jsem, že obě smyčky upozorní „číslo“ třikrát. Jak je první smyčka implementována v JavaScriptu? Jinými slovy, pokud for-each je syntaktický cukr, jaký je jeho ekvivalent při použití standardní smyčky?

Existuje také nějaký způsob, jak iterovat jmenný prostor objektu pomocí standardní smyčky? Chci se dotknout všech metod a atributů některých objektů pomocí smyčky druhého druhu.

Odpověď

Důvod, proč se vám v první smyčce vrací „řetězec“, je num odkazuje na index pole , nikoli hodnotu numarray u toho indexu. Zkuste změnit první smyčku na upozornění num místo typeof num a uvidíte, že vyplivne 0, 1 a 2, což jsou indexy, nikoli hodnoty vašeho pole.

Když použijete for in smyčky, iterujete vlastnosti objektu, což není přesně ekvivalentní for smyčka ve vašem druhém příkladu. Pole v JavaScriptu jsou ve skutečnosti pouze objekty se sekvenčními čísly jako názvy vlastností. Jsou považovány za řetězce až do typeof je znepokojen.

Upravit:

Jak zdůrazňuje Matthew, při použití for in není zaručeno, že položky v poli získáte v jakémkoli konkrétním pořadí. smyčky a částečně z tohoto důvodu se nedoporučuje iterovat pole tímto způsobem.

filip-fku se ptá, kdy by bylo užitečné použít for in vzhledem k tomuto chování. Jedním z příkladů je, když mají význam samotná jména vlastností, což ve skutečnosti není případ indexů pole. Například:

var myName = {
  first: 'Jimmy',
  last: 'Cuadra'
};

for (var prop in myName) {
  console.log(prop + ': ' + myName[prop]);
}

// prints:
// first: Jimmy
// last: Cuadra

Za zmínku také stojí for in smyčky budou také iterovat prostřednictvím vlastností řetězce prototypu objektu. Z tohoto důvodu byste obvykle chtěli vytvořit for in takto smyčka:

for (var prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    // do something
  }
}

Tím se zkontroluje, zda vlastnost byla definována samotným objektem a ne objektem, který dědí prostřednictvím řetězce prototypu.