Elementos por ordem de um “para (... em ...)” Lacete
-
07-07-2019 - |
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
Solução
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.
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 .