2008-11-11 10 views
174

¿El bucle "for ... in" en Javascript se repite a través de las tablas/elementos en el orden en que se declaran? ¿Hay un navegador que no lo hace en orden?
El objeto que deseo utilizar se declarará una vez y nunca se modificará.Orden de elementos en un bucle "for (... in ...)"

Supongamos que tengo:

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

Y uso aún más en:

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

puedo esperar 'A: "Hola"' siempre que venir antes 'B: "Mundial"' en la mayoría de los navegadores decentes?

+59

robaba sólo serían probando un subconjunto de los navegadores potenciales y variantes. Por no hablar de futuros navegadores. Es completamente erróneo suponer que una prueba que no falla proporciona ningún tipo de prueba concreta. –

+6

Dudo que mi propia capacidad limitada de javascript sea mejor que la del SO. Además, ¿quién sabe qué navegador extraño acecha por ahí? Y puede ver en la respuesta que GChrome tiene un error que no será aparente en mi caso de ejemplo simple. – chakrit

+0

posible duplicado de [¿Tiene el pedido de propiedad del objeto de garantía de JavaScript?] (Http://stackoverflow.com/q/5525795/1048572) – Bergi

Respuesta

191

Quoting John Resig:

Actualmente todos los principales bucle navegadores sobre las propiedades de un objeto en el orden en que se definieron. Chrome también lo hace, excepto en un par de casos. [...] Este comportamiento queda explícitamente indefinido 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 se definieron. Debido a esto, el equipo de Chrome ha considerado que esto es un error y lo arreglará.

Todos los navegadores respetan la orden de definición with the exception of Chrome y Opera que hacen para cada nombre de propiedad no numérico. En estos dos navegadores, las propiedades se ordenan antes de la primera propiedad no numérica (esto tiene que ver con la forma en que implementan las matrices). El orden es el mismo para Object.keys también.

En este ejemplo se debe dejar en 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 aspectos técnicos de ello son menos importantes que el hecho de que esto puede cambiar en cualquier momento. No confíes en que las cosas se mantengan de esta manera.

En resumen: Utilice una matriz si la orden es importante para usted.

+3

No realmente. Chrome no implementa el mismo orden que otros navegadores: http://code.google.com/p/v8/issues/detail?id=164 –

+0

@Tim, gracias por el empujón. He actualizado la respuesta para reflejar el estado actual de la realidad. – Borgar

+15

"Use una matriz si la orden es importante para usted": ¿Qué sucede cuando usa JSON? – HM2K

10

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

No se cumplirán los estándares (es decir, seguros) para suponer que todas las implementaciones de Javascript se enumerarán en el orden de las declaraciones.

+2

por lo que está haciendo la pregunta, en lugar de simplemente asumir: p –

24

Desde el ECMAScript Language Specification, sección 12.6.4 (en el bucle for .. in):

La mecánica de la enumeración de las propiedades depende de la implementación. El orden de enumeración está definido por el objeto.

Y la sección 4.3.3 (definición de "objeto"):

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

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

Si quiere que se defina su orden, tendrá que implementar algo que la defina, como una matriz de claves que ordena antes de acceder el objeto con eso.

3

en IE6, la orden no se garantiza.

2

No se puede confiar en la orden. Tanto Opera como Chrome devuelven la lista de propiedades sin ordenar.

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

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

El código anterior muestra B, A, C en Opera y C, A, B en Chrome.

4

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 fijar el orden de iteración Parece que hay un deseo popular entre los desarrolladores si la discusión en http://code.google.com/p/v8/issues/detail?id=164 es cualquier indicación.

+0

¡Gracias por señalar esto! – chakrit

52

El topar esto un año después ...

Es y los principales navegadores todavía 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 test in current browser

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] 
+1

Versión verificada y agregada, IE9 y [Nodo 0.6] (http://nodejs.org/) – some

+15

¿cuál es el problema aquí? Exactamente como dice la especificación, es una lista desordenada de pares llave/val. – nickf

+0

nadie dijo que la especificación era "incorrecta" ... Existe un tratamiento molesto e incoherente en el manejo del navegador con el orden programático de acceso a estos accesorios "desordenados" – dvdrtrgn

Cuestiones relacionadas