Orden de los elementos en un bucle "for (... in...)"

Resuelto chakrit asked hace 15 años • 10 respuestas

¿El bucle "for...in" en Javascript recorre las tablas hash/elementos en el orden en que se declaran? ¿Existe algún navegador que no lo haga en orden?
El objeto que deseo usar será declarado una vez y nunca será modificado.

Supongamos que tengo:

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

Y los uso además en:

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

¿Puedo esperar que 'A: "Hola"' siempre aparezca antes de 'B: "Mundo"' en la mayoría de los navegadores decentes?

chakrit avatar Nov 11 '08 19:11 chakrit
Aceptado

Citando a John Resig :

Actualmente, todos los navegadores principales recorren las propiedades de un objeto en el orden en que fueron definidas. Chrome también hace esto, excepto en un par de casos. [...] Este comportamiento no está definido explícitamente por la especificación ECMAScript. En ECMA-262, sección 12.6.4:

La mecánica de enumerar las propiedades... depende de la implementación.

Sin embargo, la especificación es bastante diferente de la implementación. Todas las implementaciones modernas de ECMAScript iteran a través de las propiedades del objeto en el orden en que fueron definidas. Debido a esto, el equipo de Chrome ha considerado que se trata de un error y lo solucionará.

Todos los navegadores respetan el orden de las definiciones, a excepción de Chrome y Opera, que lo hacen para todos los nombres de propiedad no numéricos. En estos dos navegadores, las propiedades se ordenan antes de la primera propiedad no numérica (esto tiene que ver con cómo implementan las matrices). El orden es el mismo para Object.keystambién.

Este ejemplo debería dejar claro lo que sucede:

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"

Los detalles técnicos de esto son menos importantes que el hecho de que esto puede cambiar en cualquier momento. No confíes en que las cosas sigan así.

En resumen: utilice una matriz si el orden es importante para usted.

Borgar avatar Nov 11 '2008 13:11 Borgar

Topando esto un año después...

Estamos en 2012 y los principales navegadores aún difieren:

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 o prueba en el navegador actual

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, Nodo 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] 
dvdrtrgn avatar Jan 02 '2012 19:01 dvdrtrgn

De la Especificación del lenguaje ECMAScript , sección 12.6.4 (en el for .. inbucle):

La mecánica de enumerar las propiedades depende de la implementación. El orden de enumeración lo define el objeto.

Y el apartado 4.3.3 (definición de "Objeto"):

Es una colección desordenada de propiedades, cada una de las cuales contiene un valor, objeto o función primitivo. Una función almacenada en una propiedad de un objeto se llama método.

Supongo que eso significa que no puedes confiar en que las propiedades se enumeren en un orden coherente en todas las implementaciones de JavaScript. (De todos modos, sería de mal estilo confiar en los detalles específicos de la implementación de un lenguaje).

Si desea que se defina su orden, deberá implementar algo que lo defina, como una matriz de claves que ordene antes de acceder al objeto con ella.

Tomalak avatar Nov 11 '2008 12:11 Tomalak

Los elementos de un objeto que enumera for/in son las propiedades que no tienen establecido el indicador DontEnum. El estándar ECMAScript, también conocido como Javascript, dice explícitamente que "Un objeto es una colección desordenada de propiedades" (consulte http://www.mozilla.org/js/language/E262-3.pdf sección 8.6).

No será conforme a los estándares (es decir, seguro) asumir que todas las implementaciones de Javascript se enumerarán en el orden de declaración.

Adam Wright avatar Nov 11 '2008 12:11 Adam Wright

El orden de iteración también se confunde con respecto a la eliminación de propiedades, pero en este caso solo con IE.

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
}

El deseo de cambiar la especificación para arreglar el orden de iteración parece ser un deseo bastante popular entre los desarrolladores si la discusión en http://code.google.com/p/v8/issues/detail?id=164 es una indicación.

Brett Zamir avatar Jan 04 '2011 07:01 Brett Zamir