Pergunta

A "for ... in" loop no circuito de Javascript através das tabelas de hash / elementos na ordem em que são declarados? Existe um navegador que não fazê-lo em ordem?
O objeto Desejo uso será declarado uma vez e nunca será modificado.

Suponha que eu tenho:

var myObject = { A: "Hello", B: "World" };

E eu usá-los ainda mais em:

for (var item in myObject) alert(item + " : " + myObject[item]);

Posso esperar 'A: "Olá"' para sempre vêm antes 'B: "World"'? Na maioria dos navegadores decentes

Foi útil?

Solução

Citando John Resig :

Atualmente todos os principais navegadores de loop sobre as propriedades de um objeto na ordem em os quais foram definidos. Chrome faz isso bem, com exceção de casos casal. [...] Este comportamento é explicitamente deixado sem definição pela especificação ECMAScript. Em ECMA-262, seção 12.6.4:

A mecânica de enumerar as propriedades ... é dependente de implementação.

No entanto, a especificação é bastante diferente da implementação. Todas as implementações modernas de ECMAScript iterar propriedades do objecto, na ordem em que foram definidos. Devido a isso a equipe Chrome considerou que este é um bug e será corrigi-lo.

Todos os navegadores respeitar a ordem definição com exceção da Chrome e Opera que fazer para cada nome de propriedade não-numérica. Nestes dois navegadores as propriedades são puxados em ordem antes da primeira propriedade não-numérica (isto é tem a ver com a forma como eles implementam matrizes). A ordem é a mesma para Object.keys também.

Este exemplo deve deixar claro o que acontece:

var obj = {
  "first":"first",
  "2":"2",
  "34":"34",
  "1":"1",
  "second":"second"
};
for (var i in obj) { console.log(i); };
// Order listed:
// "1"
// "2"
// "34"
// "first"
// "second"

Os aspectos técnicos deste são menos importantes do que o fato de que isso pode mudar a qualquer momento. Não confiar em coisas que ficam desta forma.

Em resumo:. Use um array se a ordem é importante para você

Outras dicas

Bumping este um ano mais tarde ...

É 2012 e os principais navegadores ainda diferem:

function lineate(obj){
    var arr = [], i;
    for (i in obj) arr.push([i,obj[i]].join(':'));
    console.log(arr);
}
var obj = { a:1, b:2, c:3, "123":'xyz' };
/* log1 */  lineate(obj);
obj.a = 4;
/* log2 */  lineate(obj);
delete obj.a;
obj.a = 4;
/* log3 */  lineate(obj);

essência ou teste no navegador atual

Safari 5, Firefox 14

["a:1", "b:2", "c:3", "123:xyz"]
["a:4", "b:2", "c:3", "123:xyz"]
["b:2", "c:3", "123:xyz", "a:4"]

Chrome 21, Opera 12, Node 0.6, Firefox 27

["123:xyz", "a:1", "b:2", "c:3"]
["123:xyz", "a:4", "b:2", "c:3"]
["123:xyz", "b:2", "c:3", "a:4"]

IE9

[123:xyz,a:1,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 

A partir da ECMAScript Idioma Specification , secção 12.6.4 (no loop for .. in):

A mecânica de enumerar as propriedades é dependente de implementação. A ordem de enumeração é definida pelo objeto.

E ponto 4.3.3 (definição de "Objeto"):

É uma colecção não ordenada das propriedades de cada um dos quais contém um valor primitivo, objeto, ou função. A função armazenada em uma propriedade de um objeto é chamado de método.

Eu acho que significa que você não pode contar com as propriedades a ser enumerados numa ordem consistente em implementações de JavaScript. (Seria um estilo ruim de qualquer maneira para contar com detalhes específicos de implementação de uma língua.)

Se você quiser que o seu fim definido, será necessário implementar algo que o define, como um conjunto de chaves que você classificar antes de acessar o objeto com ele.

Os elementos de um objeto que for / em enumera são as propriedades que não têm a flag DontEnum. O ECMAScript, aka Javascript, padrão explicitamente diz que "um objeto é uma coleção desordenada de propriedades" (ver http://www.mozilla.org/js/language/E262-3.pdf secção 8.6).

Não vai ser normas conformant (cofre ou seja) para assumir todas as implementações de JavaScript irá enumerar em ordem de declaração.

fim

A iteração também é confundido com relação à eliminação de propriedades, mas neste caso com o IE somente.

var obj = {};
obj.a = 'a';
obj.b = 'b';
obj.c = 'c';

// IE allows the value to be deleted...
delete obj.b;

// ...but remembers the old position if it is added back later
obj.b = 'bb';
for (var p in obj) {
    alert(obj[p]); // in IE, will be a, bb, then c;
                   // not a, c, then bb as for FF/Chrome/Opera/Safari
}

O desejo de mudar a especificação para fixar a ordem de iteração parece ser um desejo bastante popular entre os desenvolvedores se a discussão em http://code.google.com/p/v8/issues/detail?id=164 é qualquer indicação.

no IE6, a ordem é não garantida.

A ordem não pode ser confiável. Ambos Opera e Chrome retornar a lista de propriedades não-ordenada.

<script type="text/javascript">
var username = {"14719":"A","648":"B","15185":"C"};

for (var i in username) {
  window.alert(i + ' => ' + username[i]);
}
</script>

O código acima mostra B, A, C em Opera e C, A, B, em cromo.

Isto não responder à pergunta em si, mas oferece uma solução para o problema básico.

Supondo que você não pode confiar em fim de preservado, por que não usar um array de objetos com chave e valor como propriedades?

var myArray = [
    {
        'key'   : 'key1'
        'value' : 0
    },
    {
        'key'   : 'key2',
        'value' : 1
    } // ...
];

Agora, cabe a você para garantir que as chaves são únicas (assumindo que isso também é importante para você. Assim, alterações de endereçamento direto, e para (... em ...) agora retorna índices como ' chaves.

> console.log(myArray[0].key);
key1

> for (let index in myArray) {console.log(myArray[index].value);}
0
1
Veja o Pen para (... em ...) abordando a fim por JDQ ( @JDQ ) em CodePen .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top