web-dev-qa-db-fra.com

Ordre des éléments dans une boucle "for (… in ...)"

La boucle "for ... in" en Javascript parcourt-elle les hashtables/éléments dans leur ordre de déclaration? Y a-t-il un navigateur qui ne le fait pas dans l'ordre?
L'objet que je souhaite utiliser sera déclaré une fois et ne sera jamais modifié.

Supposons que j'ai:

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

Et je les utilise ensuite dans:

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

Puis-je m'attendre à ce que "A:" Bonjour "vienne toujours avant" B: "Monde" "dans la plupart des navigateurs convenables?

189
chakrit

Citant John Resig :

Actuellement, tous les principaux navigateurs parcourent les propriétés d'un objet dans l'ordre suivant qui ils ont été définis. Chrome le fait également, sauf dans quelques cas. [...] Ce comportement est explicitement laissé indéfini par la spécification ECMAScript. Dans l'ECMA-262, section 12.6.4:

La mécanique d'énumération des propriétés ... dépend de la mise en œuvre.

Cependant, la spécification est assez différente de la mise en œuvre. Toutes les implémentations modernes de ECMAScript itérer à travers les propriétés d'objet dans l'ordre dans lequel elles ont été définies. Pour cette raison, l'équipe de Chrome a estimé qu'il s'agissait d'un bug et le corrigera.

Tous les navigateurs respectent l'ordre de définition à l'exception de Chrome et Opera, qui le font pour tous les noms de propriété non numériques. Dans ces deux navigateurs, les propriétés sont placées dans l'ordre devant la première propriété non numérique (cela concerne la manière dont elles implémentent les tableaux). La commande est la même pour Object.keys.

Cet exemple devrait préciser ce qui se passe: 

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"

Les détails techniques sont moins importants que le fait que cela peut changer à tout moment. Ne comptez pas sur les choses en restant ainsi.

En bref: Utilisez un tableau si l'ordre est important pour vous.

200
Borgar

_ {Bumping this un an plus tard ... _

Il est 2012 et les principaux navigateurs still diffèrent:

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);

Gist ou test dans le navigateur actuel

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] 
53
dvdrtrgn

À partir de Spécification de langage ECMAScript , section 12.6.4 (sur la boucle for .. in):

La mécanique d'énumération des propriétés dépend de la mise en œuvre. L'ordre d'énumération est défini par l'objet.

Et section 4.3.3 (définition du terme "objet"):

C'est une collection non ordonnée de propriétés, chacune contenant une valeur primitive, un objet ou une fonction. Une fonction stockée dans une propriété d'un objet s'appelle une méthode.

Je suppose que cela signifie que vous ne pouvez pas compter sur les propriétés énumérées dans un ordre cohérent pour toutes les implémentations de JavaScript. (Ce serait de toute façon un mauvais style de s'appuyer sur les détails d'un langage spécifiques à l'implémentation.)

Si vous souhaitez que votre commande soit définie, vous devez implémenter quelque chose qui la définit, comme un tableau de clés que vous triez avant d'accéder à l'objet avec celle-ci.

26
Tomalak

Les éléments d'un objet énuméré pour/dans sont les propriétés pour lesquelles l'indicateur DontEnum n'est pas défini. Le standard ECMAScript, également appelé Javascript, indique explicitement que "Un objet est une collection non ordonnée de propriétés" (voir http://www.mozilla.org/js/language/E262-3.pdf section 8.6).

Il ne va pas y avoir de conformité aux normes (c'est-à-dire sans danger) si toutes les implémentations Javascript sont énumérées dans l'ordre des déclarations.

10
Adam Wright

L'ordre des itérations est également confus en ce qui concerne la suppression de propriétés, mais dans ce cas avec IE uniquement.

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
}

Le désir de modifier les spécifications pour corriger l'ordre d'itération semble être un désir très répandu parmi les développeurs si la discussion à http://code.google.com/p/v8/issues/detail?id=164 est aucune indication.

4
Brett Zamir

dans IE6, la commande n'est pas garantie. 

3
Ari

L'ordre ne peut pas être approuvé. Opera et Chrome renvoient tous deux la liste des propriétés non ordonnées.

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

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

Le code ci-dessus montre B, A, C dans Opera et C, A, B dans Chrome.

2
Kouber Saparev