Vi la pregunta reciente en la que alguien te dijo eso, pero solo significaban para matrices. Se considera una mala práctica para iterar a través de matrices, pero no necesariamente para iterar a través de miembros de un objeto.
mmurch
19
Muchas respuestas con bucles "for" como 'for (var i = 0; i <hColl.length; i ++) {}' compare con 'var i = hColl.length; mientras que (i--) {} 'que, cuando es posible usar la última forma, es sustancialmente más rápido. Sé que esto es tangencial, pero pensé que agregaría este bit.
Mark Schultheiss
2
@ MarkSchultheiss pero eso es iteración inversa. ¿Hay otra versión de iteración hacia adelante que sea más rápida?
ma11hew28
55
@Wynand use var i = hCol1.length; for (i;i;i--;) {}caché i ya que hará la diferencia y simplificará la prueba. - cuanto más antiguo es el navegador, más diferencia hay fory whileSIEMPRE almacena en caché el contador "i" - y, por supuesto, lo negativo no siempre se ajusta a la situación, y lo negativo es obfuscate un poco el código para algunas personas. y tenga en cuenta var i = 1000; for (i; i; i--) {}y var b =1000 for (b; b--;) {}donde voy de 1000 a 1 yb va de 999 a 0. - cuanto más antiguo es el navegador, más tiempo tiende a favorecer el rendimiento.
Mark Schultheiss
99
También puedes ser inteligente. for(var i = 0, l = myArray.length; i < l; ++i) ...es lo más rápido y mejor que puede obtener con la iteración hacia adelante.
Mathieu Amiot
Respuestas:
1557
La razón es que una construcción:
var a =[];// Create a new empty array.
a[5]=5;// Perfectly legal JavaScript that resizes the array.for(var i =0; i < a.length; i++){// Iterate over numeric indexes from 0 to 5, as everyone expects.
console.log(a[i]);}/* Will display:
undefined
undefined
undefined
undefined
undefined
5
*/
También tenga en cuenta que las bibliotecas de JavaScript pueden hacer cosas como esta, lo que afectará cualquier matriz que cree:
// Somewhere deep in your JavaScript library...Array.prototype.foo =1;// Now you have no idea what the below code will do.var a =[1,2,3,4,5];for(var x in a){// Now foo is a part of EVERY array and // will show up here as a value of 'x'.
console.log(x);}/* Will display:
0
1
2
3
4
foo
*/
¡Históricamente, algunos navegadores incluso iteraron sobre 'length', 'toString', etc.!
bobince 01 de
398
Recuerde usar en (var x in a)lugar de (x in a)- no quiere crear un global.
Chris Morgan
78
El primer problema no es una razón por la que es malo, solo una diferencia en la semántica. El segundo problema me parece una razón (además de los enfrentamientos entre bibliotecas que hacen lo mismo) de que alterar el prototipo de un tipo de datos incorporado es malo, en lugar de eso para ... en es malo.
Stewart
86
@ Stewart: Todos los objetos en JS son asociativos. Un JS Array es un objeto, así que sí, también es asociativo, pero no es para eso. Si desea iterar sobre las teclas de un objeto , use for (var key in object). Sin embargo, si desea iterar sobre los elementos de una matriz , úselos for(var i = 0; i < array.length; i += 1).
Martijn
42
Usted dijo para el primer ejemplo, que Itera sobre índices numéricos de 0 a 4, como todos esperan , ¡ espero que repita de 0 a 5 ! Dado que si agrega un elemento en la posición 5, la matriz tendrá 6 elementos (5 de ellos sin definir).
stivlo
393
La for-indeclaración en sí misma no es una "mala práctica", sin embargo, puede usarse mal , por ejemplo, para iterar sobre matrices u objetos similares a las matrices.
El propósito de la for-indeclaración es enumerar las propiedades de los objetos. Esta declaración subirá en la cadena del prototipo, enumerando también las propiedades heredadas , algo que a veces no se desea.
Además, el orden de iteración no está garantizado por la especificación, lo que significa que si desea "iterar" un objeto de matriz, con esta declaración no puede estar seguro de que las propiedades (índices de matriz) se visitarán en orden numérico.
Por ejemplo, en JScript (IE <= 8), el orden de enumeración incluso en los objetos Array se define como se crearon las propiedades:
var array =[];
array[2]='c';
array[1]='b';
array[0]='a';for(var p in array){//... p will be "2", "1" and "0" on IE}
Además, hablando de propiedades heredadas, si, por ejemplo, extiende el Array.prototypeobjeto (como algunas bibliotecas como lo hacen MooTools), esas propiedades también se enumerarán:
Array.prototype.last =function(){returnthis[this.length-1];};for(var p in []){// an empty array// last will be enumerated}
Como dije antes para iterar sobre matrices u objetos similares a matrices, lo mejor es usar un bucle secuencial , como un bucle for/ old simple while.
Cuando desee enumerar solo las propiedades propias de un objeto (las que no se heredan), puede usar el hasOwnPropertymétodo:
for(var prop in obj){if(obj.hasOwnProperty(prop)){// prop is not inherited}}
Y algunas personas incluso recomiendan llamar al método directamente Object.prototypepara evitar tener problemas si alguien agrega una propiedad nombrada hasOwnPropertya nuestro objeto:
for(var prop in obj){if(Object.prototype.hasOwnProperty.call(obj, prop)){// prop is not inherited}}
Pregunta sobre el último punto sobre "hasOwnProperty": si alguien anula "hasOwnProperty" en un objeto, tendrá problemas. ¿Pero no tendrá los mismos problemas si alguien anula "Object.prototype.hasOwnProperty"? De cualquier manera, te están jodiendo y no es tu responsabilidad, ¿verdad?
Scott Rippey
Dices for..inque no es una mala práctica, pero puede ser mal utilizada. ¿Tienes un ejemplo de buenas prácticas en el mundo real, en el que realmente querías revisar todas las propiedades de un objeto, incluidas las propiedades heredadas?
con esta respuesta encontré que puede acceder al valor confor (var p in array) { array[p]; }
equiman
117
Hay tres razones por las que no debe usar for..inpara iterar sobre elementos de la matriz:
for..inrecorrerá todas las propiedades propias y heredadas del objeto de matriz que no lo sean DontEnum; eso significa que si alguien agrega propiedades al objeto de matriz específico (hay razones válidas para esto, lo he hecho yo mismo) o ha cambiado Array.prototype(lo que se considera una mala práctica en el código que se supone que funciona bien con otros scripts), estas propiedades funcionarán ser iterado también; Las propiedades heredadas se pueden excluir marcando hasOwnProperty(), pero eso no lo ayudará con las propiedades establecidas en el objeto de matriz.
for..in no se garantiza que conserve el orden de los elementos
es lento porque tiene que recorrer todas las propiedades del objeto de matriz y toda su cadena de prototipos y solo obtendrá el nombre de la propiedad, es decir, para obtener el valor, se requerirá una búsqueda adicional
Porque for ... in enumera a través del objeto que contiene la matriz, no la matriz en sí. Si agrego una función a la cadena de prototipos de matrices, eso también se incluirá. Es decir
Array.prototype.myOwnFunction =function(){ alert(this);}
a =newArray();
a[0]='foo';
a[1]='bar';for(x in a){
document.write(x +' = '+ a[x]);}
Esto escribirá:
0 = foo
1 = barra
myOwnFunction = function () {alert (this); }
Y dado que nunca puede estar seguro de que no se agregará nada a la cadena de prototipos, solo use un bucle for para enumerar la matriz:
Las matrices son objetos, no existe un "objeto que contenga la matriz".
RobG
41
De forma aislada, no hay nada de malo en usar for-in en matrices. For-in itera sobre los nombres de propiedad de un objeto, y en el caso de una matriz "lista para usar", las propiedades corresponden a los índices de la matriz. (Las propiedades incorporadas length, como , toStringetc., no se incluyen en la iteración).
Sin embargo, si su código (o el marco que está utilizando) agrega propiedades personalizadas a las matrices o al prototipo de la matriz, estas propiedades se incluirán en la iteración, que probablemente no sea lo que desea.
Algunos marcos JS, como Prototype, modifican el prototipo Array. Otros marcos como JQuery no lo hacen, por lo que con JQuery puedes usar for-in de forma segura.
Si tiene dudas, probablemente no debería usar for-in.
Una forma alternativa de iterar a través de una matriz es usar un bucle for:
for(var ix=0;ix<arr.length;ix++) alert(ix);
Sin embargo, esto tiene un problema diferente. El problema es que una matriz de JavaScript puede tener "agujeros". Si define arrcomo:
var arr =["hello"];
arr[100]="goodbye";
Luego, la matriz tiene dos elementos, pero una longitud de 101. El uso de for-in producirá dos índices, mientras que el for-loop producirá 101 índices, donde el 99 tiene un valor de undefined.
Respuesta más larga: simplemente no vale la pena, incluso si no se requiere un orden secuencial de elementos y un rendimiento óptimo.
Respuesta larga: simplemente no vale la pena ...
El uso for (var property in array)hará arrayque se repita como un objeto , atravesando la cadena del prototipo del objeto y, en última instancia, funcionando más lentamente que un forbucle basado en índice .
for (... in ...) no se garantiza que devuelva las propiedades del objeto en orden secuencial, como cabría esperar.
El uso hasOwnProperty()y las !isNaN()comprobaciones para filtrar las propiedades del objeto es una sobrecarga adicional que hace que funcione aún más lentamente y niega la razón clave para usarlo en primer lugar, es decir, debido al formato más conciso.
Por estas razones, ni siquiera existe una compensación aceptable entre rendimiento y conveniencia. Realmente no hay ningún beneficio a menos que la intención sea manejar la matriz como un objeto y realizar operaciones en las propiedades del objeto de la matriz.
Además de las razones dadas en otras respuestas, es posible que no desee usar la estructura "for ... in" si necesita hacer cálculos matemáticos con la variable de contador porque el ciclo itera a través de los nombres de las propiedades del objeto y, por lo tanto, la variable es una cuerda
Puede usar el prefijo en +lugar de a parseIntmenos que realmente necesite un número entero o ignore caracteres no válidos.
Konrad Borowski
Además, parseInt()no se recomienda su uso. Pruebe parseInt("025");y se le fallará.
Derek 朕 會 功夫
66
@Derek 朕 會 功夫: definitivamente puedes usarlo parseInt. El problema es que si no incluye la raíz, los navegadores más antiguos podrían intentar interpretar el número (por lo tanto, 025 se convierte en octal). Esto se solucionó en ECMAScript 5, pero aún sucede para los números que comienzan con "0x" (interpreta el número como hexadecimal). Para estar seguro, use la raíz para especificar el número de esta manera parseInt("025", 10), que especifica la base 10.
La mecánica y el orden de enumerar las propiedades ... no se especifica ...
(El énfasis es mío).
Eso significa que si un navegador quisiera, podría pasar por las propiedades en el orden en que se insertaron. O en orden numérico. O en orden léxico (¡donde "30" viene antes que "4"! Tenga en cuenta que todas las claves de objeto, y por lo tanto, todos los índices de matriz, en realidad son cadenas, por lo que tiene mucho sentido). Podría atravesarlos por cubo si implementara objetos como tablas hash. O tome algo de eso y agregue "al revés". Un navegador podría incluso iterar al azar y ser compatible con ECMA-262, siempre que visite cada propiedad exactamente una vez.
En la práctica, a la mayoría de los navegadores les gusta iterar aproximadamente en el mismo orden. Pero no hay nada que diga que tienen que hacerlo. Esa es una implementación específica, y podría cambiar en cualquier momento si se descubriera que otra forma es mucho más eficiente.
De cualquier manera, for... no inconlleva connotación de orden. Si le importa el orden, sea explícito y use un forciclo regular con un índice.
Como otros han dicho, es posible que obtenga claves que no están en su matriz o que se heredan del prototipo. Entonces, si, digamos, una biblioteca agrega una propiedad a los prototipos Array u Object:
Array.prototype.someProperty =true
Lo obtendrá como parte de cada matriz:
for(var item in [1,2,3]){
console.log(item)// will log 1,2,3 but also "someProperty"}
podrías resolver esto con el método hasOwnProperty:
var ary =[1,2,3];for(var item in ary){if(ary.hasOwnProperty(item)){
console.log(item)// will log only 1,2,3}}
pero esto es cierto para iterar sobre cualquier objeto con un ciclo for-in.
Dos
Por lo general, el orden de los elementos en una matriz es importante, pero el bucle for-in no necesariamente iterará en el orden correcto, eso es porque trata la matriz como un objeto, que es la forma en que se implementa en JS, y no como una matriz Esto parece algo pequeño, pero realmente puede arruinar las aplicaciones y es difícil de depurar.
Object.keys(a).forEach( function(item) { console.log(item) } )iterar sobre una matriz de claves de propiedad propias, no las heredadas del prototipo.
Qwerty
2
Es cierto, pero al igual que el ciclo for-in, no necesariamente estará en el orden de índice correcto. Además, no funcionará en navegadores antiguos que no admitan ES5.
En firefox 3 también puede usar arr.forEach o for (var [i, v] en Iterator (arr)) {} pero ninguno de esos funciona en IE, aunque puede escribir para cada método usted mismo.
vava
y prácticamente todas las bibliotecas tienen su propio método para esto también.
vava
55
Esta respuesta es incorrecta. "longitud" no se incluirá en la iteración for-in. Solo se incluyen las propiedades que agrega usted mismo.
Sin embargo, me gustaría agregar que en los navegadores modernos hay una alternativa for...inque se puede usar en aquellos casos en los for...inque no se puede usar. Esa alternativa es for...of:
for(var item of items){
console.log(item);}
Nota :
Desafortunadamente, ninguna versión de Internet Explorer es compatible for...of( Edge 12+ lo hace), por lo que tendrá que esperar un poco más hasta que pueda usarla en el código de producción del lado del cliente. Sin embargo, debería ser seguro usarlo en el código JS del lado del servidor (si usa Node.js ).
@georgeawg Querías decir for-of, no for-in, ¿verdad?
ᆼ ᆺ ᆼ
15
El problema con for ... in ...- y esto solo se convierte en un problema cuando un programador realmente no entiende el lenguaje; en realidad no es un error ni nada, es que itera sobre todos los miembros de un objeto (bueno, todos los miembros enumerables , pero eso es un detalle por ahora). Cuando desee iterar solo sobre las propiedades indexadas de una matriz, la única forma garantizada de mantener las cosas semánticamente consistentes es usar un índice entero (es decir, un for (var i = 0; i < array.length; ++i)bucle de estilo).
Cualquier objeto puede tener propiedades arbitrarias asociadas a él. No habría nada terrible en cargar propiedades adicionales en una instancia de matriz, en particular. El código que quiere ver solo propiedades indexadas de tipo matriz, por lo tanto, debe adherirse a un índice entero. Código que es plenamente consciente de lo for ... inque realmente necesita ver todas las propiedades, bueno, eso también está bien.
Buena explicación puntiaguda. Sólo curioso. Si tuviera una matriz que estaba dentro de un objeto bajo propiedades de multiplicación y for in, en comparación con un ciclo for regular, ¿esas matrices se iterarían? (lo que en esencia sería un rendimiento lento, ¿verdad?)
NiCk Newman
2
@NiCkNewman bien, el objeto al que hace referencia inen un for ... inbucle simplemente
Pointy
Veo. Simplemente curioso porque tengo objetos y matrices dentro de mi objeto principal del juego y me preguntaba si para la entrada sería más doloroso que simplemente un ciclo for regular en los índices.
NiCk Newman
@NiCkNewman, bueno, el tema de toda esta pregunta es que simplemente no debes usarlo for ... inen matrices; Hay muchas buenas razones para no hacerlo. No es tanto un problema de rendimiento como un problema de "asegúrese de que no se rompa".
Puntiagudo
Bueno, mis objetos se almacenan técnicamente en una matriz, por eso estaba preocupado, algo así como: [{a:'hey',b:'hi'},{a:'hey',b:'hi'}]pero sí, lo entiendo.
NiCk Newman
9
Además, debido a la semántica, la forma en que for, intrata las matrices (es decir, lo mismo que cualquier otro objeto JavaScript) no está alineada con otros lenguajes populares.
// C#char[] a =newchar[]{'A','B','C'};
foreach (char x in a)System.Console.Write(x);//Output: "ABC"// Javachar[] a ={'A','B','C'};for(char x : a)System.out.print(x);//Output: "ABC"// PHP
$a = array('A','B','C');
foreach ($a as $x) echo $x;//Output: "ABC"// JavaScriptvar a =['A','B','C'];for(var x in a) document.write(x);//Output: "012"
TL&DR: Usar el for inbucle en matrices no es malo, de hecho, todo lo contrario.
Creo que el for inbucle es una joya de JS si se usa correctamente en matrices. Se espera que tenga control total sobre su software y sepa lo que está haciendo. Veamos los inconvenientes mencionados y refutemos uno por uno.
También recorre las propiedades heredadas: en primer lugar, cualquier extensión de la Array.prototypedebe haberse realizado mediante el uso Object.defineProperty()y su enumerabledescriptor debe establecerse en false. Cualquier biblioteca que no lo haga no debe usarse en absoluto.
Las propiedades que agrega a la cadena de herencia más tarde se cuentan: al hacer una subclasificación de matrices por Object.setPrototypeOfo por clase extend. Debe utilizar una vez más Object.defineProperty(), que por defecto los conjuntos writable, enumerabley los configurabledescriptores de propiedades a false. Veamos un ejemplo de subclasificación de matriz aquí ...
functionStack(...a){var stack =newArray(...a);Object.setPrototypeOf(stack,Stack.prototype);return stack;}Stack.prototype =Object.create(Array.prototype);// now stack has full access to array methods.Object.defineProperty(Stack.prototype,"constructor",{value:Stack});// now Stack is a proper constructorObject.defineProperty(Stack.prototype,"peak",{value:function(){// add Stack "only" methods to the Stack.prototype.returnthis[this.length-1];}});var s =newStack(1,2,3,4,1);
console.log(s.peak());
s[s.length]=7;
console.log("length:",s.length);
s.push(42);
console.log(JSON.stringify(s));
console.log("length:",s.length);for(var i in s) console.log(s[i]);
Así que ya ves ... el for inbucle ahora es seguro ya que te importa tu código.
El for inciclo es lento: infierno no. Es, con mucho, el método de iteración más rápido si realiza un bucle sobre matrices dispersas que se necesitan de vez en cuando. Este es uno de los trucos de rendimiento más importantes que uno debe saber. Veamos un ejemplo. Vamos a recorrer un conjunto disperso.
var a =[];
a[0]="zero";
a[10000000]="ten million";
console.time("for loop on array a:");for(var i=0; i < a.length; i++) a[i]&& console.log(a[i]);
console.timeEnd("for loop on array a:");
console.time("for in loop on array a:");for(var i in a) a[i]&& console.log(a[i]);
console.timeEnd("for in loop on array a:");
@ Ravi Shanker Reddy Buena configuración de benchmarking. Como he mencionado en mi respuesta, el for inbucle eclipsa a los demás "si" la matriz es escasa y más si se hace más grande. Así que he reorganizado la prueba de banco para una matriz dispersa arr, de tamaño ~ 10000 con solo 50 elementos elegidos [42,"test",{t:1},null, void 0]al azar entre índices aleatorios. Notará inmediatamente la diferencia. - >> Compruébalo aquí << - .
Reducir el
8
Además de los otros problemas, la sintaxis "for..in" es probablemente más lenta, porque el índice es una cadena, no un entero.
var a =["a"]for(var i in a)
alert(typeof i)// 'string'for(var i =0; i < a.length; i++)
alert(typeof i)// 'number'
Probablemente no importa mucho. Los elementos de matriz son propiedades de un objeto basado en matriz o similar a una matriz, y todas las propiedades de objeto tienen claves de cadena. A menos que su motor JS lo optimice de alguna manera, incluso si usara un número, terminaría convirtiéndose en una cadena para la búsqueda.
cHao
Independientemente de cualquier problema de rendimiento, si es nuevo en JavaScript, use var i in ay espere que el índice sea un número entero, entonces hacer algo como a[i+offset] = <value>colocar los valores en lugares completamente incorrectos. ("1" + 1 == "11").
szmoore
8
Un aspecto importante es que for...insolo itera sobre las propiedades contenidas en un objeto que tienen su atributo de propiedad enumerable establecido en verdadero. Entonces, si uno intenta iterar sobre un objeto usando, entonces se pueden perder propiedades arbitrarias si su atributo de propiedad enumerable es falso. Es muy posible alterar el atributo de propiedad enumerable para los objetos Array normales para que ciertos elementos no se enumeren. Aunque, en general, los atributos de propiedad tienden a aplicarse a las propiedades de función dentro de un objeto.for...in
Se puede verificar el valor del atributo de propiedad enumerable de una propiedad de la siguiente manera:
Esta es una característica disponible en ECMAScript 5: en versiones anteriores no era posible alterar el valor del atributo de propiedad enumerable (siempre se estableció en verdadero).
El for/in funciona con dos tipos de variables: tablas hash (matrices asociativas) y matrices (no asociativas).
JavaScript determinará automáticamente la forma en que pasa a través de los elementos. Entonces, si sabe que su matriz es realmente no asociativa, puede usarfor (var i=0; i<=arrayLen; i++) y omitir la iteración de detección automática.
Pero en mi opinión, es mejor usar for/in , el proceso requerido para esa autodetección es muy pequeño.
Una respuesta real para esto dependerá de cómo el navegador analice / interprete el código JavaScript. Puede cambiar entre navegadores.
No puedo pensar en otros propósitos para no usar for/ in;
//Non-associativevar arr =['a','b','c'];for(var i in arr)
alert(arr[i]);//Associativevar arr ={
item1 :'a',
item2 :'b',
item3 :'c'};for(var i in arr)
alert(arr[i]);
No es suficiente: está perfectamente bien agregar propiedades con nombre arbitrarias a las instancias de matriz, y esas se probarán a truepartir de las hasOwnProperty()verificaciones.
Puntiagudo
Buen punto, gracias. Nunca he sido tan tonto como para hacerle eso a un Array, ¡así que no lo he considerado!
JAL
1
@Pointy No he probado esto, pero quizás esto se pueda superar usando un isNaNcheque en cada nombre de propiedad.
WynandB
1
@Wynand idea interesante; sin embargo, realmente no veo por qué vale la pena cuando iterar con un índice numérico simple es tan fácil.
Pointy
@WynandB perdón por el golpe, pero siento que una corrección está en orden: isNaNes para verificar si una variable es el valor especial NaN o no, no se puede usar para verificar 'cosas que no sean números' (puede ir con un regular typeof para eso).
doldt
6
No es necesariamente malo (en función de lo que está haciendo), pero en el caso de las matrices, si se ha agregado algo Array.prototype, obtendrá resultados extraños. Donde esperarías que este ciclo se ejecute tres veces:
var arr =['a','b','c'];for(var key in arr){...}
Si una función llamada helpfulUtilityMethodha sido añadido a Array's prototype, entonces el bucle terminaría corriendo cuatro veces: keysería 0, 1, 2, y helpfulUtilityMethod. Si solo esperabas números enteros, ¡ay!
Solo una nota sobre SO: no hay 'arriba' porque los comentarios cambian el orden en la página todo el tiempo. Entonces, realmente no sabemos a qué comentario te refieres. Es bueno decir "en el comentario de x persona" por este motivo.
JAL
@JAL ... o agregue el enlace permanente a la respuesta.
WynandB
5
Usar el for...inbucle para una matriz no está mal, aunque puedo adivinar por qué alguien te dijo eso:
1.) Ya existe una función o método de orden superior que tiene ese propósito para una matriz, pero tiene más funcionalidad y una sintaxis más simple, llamada 'forEach': Array.prototype.forEach(function(element, index, array) {} );
2.) Las matrices siempre tienen una longitud, pero for...iny forEachno ejecutan una función para cualquier valor que es'undefined' , sólo para los índices que tienen un valor definido. Entonces, si solo asigna un valor, estos bucles solo ejecutarán una función una vez, pero dado que se enumera una matriz, siempre tendrá una longitud hasta el índice más alto que tenga un valor definido, pero esa longitud podría pasar desapercibida al usar estos bucles
3.) El estándar for loop ejecutará una función tantas veces como usted defina en los parámetros, y dado que una matriz está numerada, tiene más sentido definir cuántas veces desea ejecutar una función. A diferencia de los otros bucles, el bucle for puede ejecutar una función para cada índice de la matriz, ya sea que el valor esté definido o no.
En esencia, puede usar cualquier bucle, pero debe recordar exactamente cómo funcionan. Comprenda las condiciones bajo las cuales los diferentes bucles reiteran, sus funcionalidades separadas, y tenga en cuenta que serán más o menos apropiados para diferentes escenarios.
Además, puede considerarse una mejor práctica usar el forEachmétodo que el for...inbucle en general, porque es más fácil de escribir y tiene más funcionalidad, por lo que es posible que desee acostumbrarse a usar solo este método y estándar para, pero su llamada.
Vea a continuación que los dos primeros bucles solo ejecutan las instrucciones console.log una vez, mientras que el bucle estándar para ejecuta la función tantas veces como se especifique, en este caso, array.length = 6.
var arr =[];
arr[5]='F';for(var index in arr){
console.log(index);
console.log(arr[index]);
console.log(arr)}// 5// 'F'// => (6) [undefined x 5, 6]
arr.forEach(function(element, index, arr){
console.log(index);
console.log(element);
console.log(arr);});// 5// 'F'// => Array (6) [undefined x 5, 6]for(var index =0; index < arr.length; index++){
console.log(index);
console.log(arr[index]);
console.log(arr);};// 0// undefined// => Array (6) [undefined x 5, 6]// 1// undefined// => Array (6) [undefined x 5, 6]// 2// undefined// => Array (6) [undefined x 5, 6]// 3// undefined// => Array (6) [undefined x 5, 6]// 4// undefined// => Array (6) [undefined x 5, 6]// 5// 'F'// => Array (6) [undefined x 5, 6]
Estas son las razones por las cuales esta (generalmente) es una mala práctica:
for...inlos bucles iteran sobre todas sus propiedades enumerables y las propiedades enumerables de sus prototipos. Por lo general, en una iteración de matriz solo queremos iterar sobre la matriz misma. Y aunque usted mismo no pueda agregar nada a la matriz, sus bibliotecas o marco pueden agregar algo.
Ejemplo :
Array.prototype.hithere ='hithere';var array =[1,2,3];for(let el in array){// the hithere property will also be iterated over
console.log(el);}
for...inlos bucles no garantizan un orden de iteración específico . Aunque este orden generalmente se ve en la mayoría de los navegadores modernos en estos días, todavía no hay una garantía del 100%.
for...inlos bucles ignoran los undefinedelementos de la matriz, es decir, los elementos de la matriz que aún no se han asignado.
Ejemplo :
const arr =[];
arr[3]='foo';// resize the array to 4
arr[4]=undefined;// add another element with value undefined to it// iterate over the array, a for loop does show the undefined elementsfor(let i =0; i < arr.length; i++){
console.log(arr[i]);}
console.log('\n');// for in does ignore the undefined elementsfor(let el in arr){
console.log(arr[el]);}
for ... in es útil cuando se trabaja en un objeto en JavaScript, pero no para un Array, pero aún así no podemos decir que sea una forma incorrecta, pero no se recomienda, mira este ejemplo a continuación usando for ... in loop:
let txt ="";const person ={fname:"Alireza", lname:"Dezfoolian", age:35};for(const x in person){
txt += person[x]+" ";}
console.log(txt);//Alireza Dezfoolian 35
OK, hagámoslo con Array ahora:
let txt ="";const person =["Alireza","Dezfoolian",35];for(const x in person){
txt += person[x]+" ";}
console.log(txt);//Alireza Dezfoolian 35
Como veis el resultado igual ...
Pero intentemos algo, prototipémonos algo para Array ...
Array.prototype.someoneelse ="someoneelse";
Ahora creamos un nuevo Array ();
let txt ="";const arr =newArray();
arr[0]='Alireza';
arr[1]='Dezfoolian';
arr[2]=35;for(x in arr){
txt += arr[x]+" ";}
console.log(txt);//Alireza Dezfoolian 35 someoneelse
Ves a alguien ! ... En realidad, estamos recorriendo un nuevo objeto Array en este caso.
Así que esa es una de las razones por las que debemos usar ... con cuidado, pero no siempre es así ...
A for ... in loop siempre enumera las claves. Las claves de propiedades de los objetos son siempre cadenas, incluso las propiedades indexadas de una matriz:
var myArray =['a','b','c','d'];var total =0for(elem in myArray){
total += elem
}
console.log(total);// 00123
Dado que los elementos de JavaScript se guardan como propiedades de objeto estándar, no es aconsejable iterar a través de matrices de JavaScript utilizando for ... en bucles porque se enumerarán los elementos normales y todas las propiedades enumerables.
aunque no se aborda específicamente en esta pregunta, agregaría que hay una muy buena razón para no usar para ... en un NodeList(como se obtendría de unquerySelectorAll llamada, ya que no ve los elementos devueltos, en su lugar iterando solo sobre las propiedades NodeList.
var i = hCol1.length; for (i;i;i--;) {}
caché i ya que hará la diferencia y simplificará la prueba. - cuanto más antiguo es el navegador, más diferencia hayfor
ywhile
SIEMPRE almacena en caché el contador "i" - y, por supuesto, lo negativo no siempre se ajusta a la situación, y lo negativo esobfuscate
un poco el código para algunas personas. y tenga en cuentavar i = 1000; for (i; i; i--) {}
yvar b =1000 for (b; b--;) {}
donde voy de 1000 a 1 yb va de 999 a 0. - cuanto más antiguo es el navegador, más tiempo tiende a favorecer el rendimiento.for(var i = 0, l = myArray.length; i < l; ++i) ...
es lo más rápido y mejor que puede obtener con la iteración hacia adelante.Respuestas:
La razón es que una construcción:
a veces puede ser totalmente diferente del otro:
También tenga en cuenta que las bibliotecas de JavaScript pueden hacer cosas como esta, lo que afectará cualquier matriz que cree:
fuente
(var x in a)
lugar de(x in a)
- no quiere crear un global.for (var key in object)
. Sin embargo, si desea iterar sobre los elementos de una matriz , úselosfor(var i = 0; i < array.length; i += 1)
.La
for-in
declaración en sí misma no es una "mala práctica", sin embargo, puede usarse mal , por ejemplo, para iterar sobre matrices u objetos similares a las matrices.El propósito de la
for-in
declaración es enumerar las propiedades de los objetos. Esta declaración subirá en la cadena del prototipo, enumerando también las propiedades heredadas , algo que a veces no se desea.Además, el orden de iteración no está garantizado por la especificación, lo que significa que si desea "iterar" un objeto de matriz, con esta declaración no puede estar seguro de que las propiedades (índices de matriz) se visitarán en orden numérico.
Por ejemplo, en JScript (IE <= 8), el orden de enumeración incluso en los objetos Array se define como se crearon las propiedades:
Además, hablando de propiedades heredadas, si, por ejemplo, extiende el
Array.prototype
objeto (como algunas bibliotecas como lo hacen MooTools), esas propiedades también se enumerarán:Como dije antes para iterar sobre matrices u objetos similares a matrices, lo mejor es usar un bucle secuencial , como un bucle
for
/ old simplewhile
.Cuando desee enumerar solo las propiedades propias de un objeto (las que no se heredan), puede usar el
hasOwnProperty
método:Y algunas personas incluso recomiendan llamar al método directamente
Object.prototype
para evitar tener problemas si alguien agrega una propiedad nombradahasOwnProperty
a nuestro objeto:fuente
for..in
es mucho más lenta que los bucles "normales".for..in
que no es una mala práctica, pero puede ser mal utilizada. ¿Tienes un ejemplo de buenas prácticas en el mundo real, en el que realmente querías revisar todas las propiedades de un objeto, incluidas las propiedades heredadas?for (var p in array) { array[p]; }
Hay tres razones por las que no debe usar
for..in
para iterar sobre elementos de la matriz:for..in
recorrerá todas las propiedades propias y heredadas del objeto de matriz que no lo seanDontEnum
; eso significa que si alguien agrega propiedades al objeto de matriz específico (hay razones válidas para esto, lo he hecho yo mismo) o ha cambiadoArray.prototype
(lo que se considera una mala práctica en el código que se supone que funciona bien con otros scripts), estas propiedades funcionarán ser iterado también; Las propiedades heredadas se pueden excluir marcandohasOwnProperty()
, pero eso no lo ayudará con las propiedades establecidas en el objeto de matriz.for..in
no se garantiza que conserve el orden de los elementoses lento porque tiene que recorrer todas las propiedades del objeto de matriz y toda su cadena de prototipos y solo obtendrá el nombre de la propiedad, es decir, para obtener el valor, se requerirá una búsqueda adicional
fuente
Porque for ... in enumera a través del objeto que contiene la matriz, no la matriz en sí. Si agrego una función a la cadena de prototipos de matrices, eso también se incluirá. Es decir
Esto escribirá:
Y dado que nunca puede estar seguro de que no se agregará nada a la cadena de prototipos, solo use un bucle for para enumerar la matriz:
Esto escribirá:
fuente
De forma aislada, no hay nada de malo en usar for-in en matrices. For-in itera sobre los nombres de propiedad de un objeto, y en el caso de una matriz "lista para usar", las propiedades corresponden a los índices de la matriz. (Las propiedades incorporadas
length
, como ,toString
etc., no se incluyen en la iteración).Sin embargo, si su código (o el marco que está utilizando) agrega propiedades personalizadas a las matrices o al prototipo de la matriz, estas propiedades se incluirán en la iteración, que probablemente no sea lo que desea.
Algunos marcos JS, como Prototype, modifican el prototipo Array. Otros marcos como JQuery no lo hacen, por lo que con JQuery puedes usar for-in de forma segura.
Si tiene dudas, probablemente no debería usar for-in.
Una forma alternativa de iterar a través de una matriz es usar un bucle for:
Sin embargo, esto tiene un problema diferente. El problema es que una matriz de JavaScript puede tener "agujeros". Si define
arr
como:Luego, la matriz tiene dos elementos, pero una longitud de 101. El uso de for-in producirá dos índices, mientras que el for-loop producirá 101 índices, donde el 99 tiene un valor de
undefined
.fuente
A partir de 2016 (ES6) podemos usar
for…of
para la iteración de matrices, como John Slegers ya notó.Solo me gustaría agregar este código de demostración simple, para aclarar las cosas:
La consola muestra:
En otras palabras:
for...of
cuenta de 0 a 5 y también ignoraArray.prototype.foo
. Muestra los valores de la matriz .for...in
enumera solo el5
, ignorando los índices de matriz indefinidos, pero agregandofoo
. Muestra los nombres de propiedades de la matriz .fuente
Respuesta corta: simplemente no vale la pena.
Respuesta más larga: simplemente no vale la pena, incluso si no se requiere un orden secuencial de elementos y un rendimiento óptimo.
Respuesta larga: simplemente no vale la pena ...
for (var property in array)
haráarray
que se repita como un objeto , atravesando la cadena del prototipo del objeto y, en última instancia, funcionando más lentamente que unfor
bucle basado en índice .for (... in ...)
no se garantiza que devuelva las propiedades del objeto en orden secuencial, como cabría esperar.hasOwnProperty()
y las!isNaN()
comprobaciones para filtrar las propiedades del objeto es una sobrecarga adicional que hace que funcione aún más lentamente y niega la razón clave para usarlo en primer lugar, es decir, debido al formato más conciso.Por estas razones, ni siquiera existe una compensación aceptable entre rendimiento y conveniencia. Realmente no hay ningún beneficio a menos que la intención sea manejar la matriz como un objeto y realizar operaciones en las propiedades del objeto de la matriz.
fuente
Además de las razones dadas en otras respuestas, es posible que no desee usar la estructura "for ... in" si necesita hacer cálculos matemáticos con la variable de contador porque el ciclo itera a través de los nombres de las propiedades del objeto y, por lo tanto, la variable es una cuerda
Por ejemplo,
escribirá
mientras,
escribirá
Por supuesto, esto se puede superar fácilmente incluyendo
en el bucle, pero la primera estructura es más directa.
fuente
+
lugar de aparseInt
menos que realmente necesite un número entero o ignore caracteres no válidos.parseInt()
no se recomienda su uso. PruebeparseInt("025");
y se le fallará.parseInt
. El problema es que si no incluye la raíz, los navegadores más antiguos podrían intentar interpretar el número (por lo tanto, 025 se convierte en octal). Esto se solucionó en ECMAScript 5, pero aún sucede para los números que comienzan con "0x" (interpreta el número como hexadecimal). Para estar seguro, use la raíz para especificar el número de esta maneraparseInt("025", 10)
, que especifica la base 10.Aparte del hecho de que
for
...in
recorre todas las propiedades enumerables (que no es lo mismo que "todos los elementos de la matriz"), consulte http://www.ecma-international.org/publications/files/ECMA-ST/Ecma -262.pdf , sección 12.6.4 (5a edición) o 13.7.5.15 (7a edición):(El énfasis es mío).
Eso significa que si un navegador quisiera, podría pasar por las propiedades en el orden en que se insertaron. O en orden numérico. O en orden léxico (¡donde "30" viene antes que "4"! Tenga en cuenta que todas las claves de objeto, y por lo tanto, todos los índices de matriz, en realidad son cadenas, por lo que tiene mucho sentido). Podría atravesarlos por cubo si implementara objetos como tablas hash. O tome algo de eso y agregue "al revés". Un navegador podría incluso iterar al azar y ser compatible con ECMA-262, siempre que visite cada propiedad exactamente una vez.
En la práctica, a la mayoría de los navegadores les gusta iterar aproximadamente en el mismo orden. Pero no hay nada que diga que tienen que hacerlo. Esa es una implementación específica, y podría cambiar en cualquier momento si se descubriera que otra forma es mucho más eficiente.
De cualquier manera,
for
... noin
conlleva connotación de orden. Si le importa el orden, sea explícito y use unfor
ciclo regular con un índice.fuente
Principalmente dos razones:
Uno
Como otros han dicho, es posible que obtenga claves que no están en su matriz o que se heredan del prototipo. Entonces, si, digamos, una biblioteca agrega una propiedad a los prototipos Array u Object:
Lo obtendrá como parte de cada matriz:
podrías resolver esto con el método hasOwnProperty:
pero esto es cierto para iterar sobre cualquier objeto con un ciclo for-in.
Dos
Por lo general, el orden de los elementos en una matriz es importante, pero el bucle for-in no necesariamente iterará en el orden correcto, eso es porque trata la matriz como un objeto, que es la forma en que se implementa en JS, y no como una matriz Esto parece algo pequeño, pero realmente puede arruinar las aplicaciones y es difícil de depurar.
fuente
Object.keys(a).forEach( function(item) { console.log(item) } )
iterar sobre una matriz de claves de propiedad propias, no las heredadas del prototipo.array.forEach
insertando cierto código en sus scripts. Ver Polyfill developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Porque enumera a través de campos de objeto, no índices. Puede obtener valor con el índice "longitud" y dudo que quiera esto.
fuente
No creo que tenga mucho que agregar, por ejemplo. La respuesta del tríptico o la respuesta del CMS sobre por qué se
for...in
debe evitar el uso en algunos casos.Sin embargo, me gustaría agregar que en los navegadores modernos hay una alternativa
for...in
que se puede usar en aquellos casos en losfor...in
que no se puede usar. Esa alternativa esfor...of
:Nota :
Desafortunadamente, ninguna versión de Internet Explorer es compatible
for...of
( Edge 12+ lo hace), por lo que tendrá que esperar un poco más hasta que pueda usarla en el código de producción del lado del cliente. Sin embargo, debería ser seguro usarlo en el código JS del lado del servidor (si usa Node.js ).fuente
for-of
, nofor-in
, ¿verdad?El problema con
for ... in ...
- y esto solo se convierte en un problema cuando un programador realmente no entiende el lenguaje; en realidad no es un error ni nada, es que itera sobre todos los miembros de un objeto (bueno, todos los miembros enumerables , pero eso es un detalle por ahora). Cuando desee iterar solo sobre las propiedades indexadas de una matriz, la única forma garantizada de mantener las cosas semánticamente consistentes es usar un índice entero (es decir, unfor (var i = 0; i < array.length; ++i)
bucle de estilo).Cualquier objeto puede tener propiedades arbitrarias asociadas a él. No habría nada terrible en cargar propiedades adicionales en una instancia de matriz, en particular. El código que quiere ver solo propiedades indexadas de tipo matriz, por lo tanto, debe adherirse a un índice entero. Código que es plenamente consciente de lo
for ... in
que realmente necesita ver todas las propiedades, bueno, eso también está bien.fuente
for in
, en comparación con un ciclo for regular, ¿esas matrices se iterarían? (lo que en esencia sería un rendimiento lento, ¿verdad?)in
en unfor ... in
bucle simplementefor ... in
en matrices; Hay muchas buenas razones para no hacerlo. No es tanto un problema de rendimiento como un problema de "asegúrese de que no se rompa".[{a:'hey',b:'hi'},{a:'hey',b:'hi'}]
pero sí, lo entiendo.Además, debido a la semántica, la forma en que
for, in
trata las matrices (es decir, lo mismo que cualquier otro objeto JavaScript) no está alineada con otros lenguajes populares.fuente
TL&DR: Usar el
for in
bucle en matrices no es malo, de hecho, todo lo contrario.Creo que el
for in
bucle es una joya de JS si se usa correctamente en matrices. Se espera que tenga control total sobre su software y sepa lo que está haciendo. Veamos los inconvenientes mencionados y refutemos uno por uno.Array.prototype
debe haberse realizado mediante el usoObject.defineProperty()
y suenumerable
descriptor debe establecerse enfalse
. Cualquier biblioteca que no lo haga no debe usarse en absoluto.Object.setPrototypeOf
o por claseextend
. Debe utilizar una vez másObject.defineProperty()
, que por defecto los conjuntoswritable
,enumerable
y losconfigurable
descriptores de propiedades afalse
. Veamos un ejemplo de subclasificación de matriz aquí ...Así que ya ves ... el
for in
bucle ahora es seguro ya que te importa tu código.for in
ciclo es lento: infierno no. Es, con mucho, el método de iteración más rápido si realiza un bucle sobre matrices dispersas que se necesitan de vez en cuando. Este es uno de los trucos de rendimiento más importantes que uno debe saber. Veamos un ejemplo. Vamos a recorrer un conjunto disperso.fuente
for in
bucle eclipsa a los demás "si" la matriz es escasa y más si se hace más grande. Así que he reorganizado la prueba de banco para una matriz dispersaarr
, de tamaño ~ 10000 con solo 50 elementos elegidos[42,"test",{t:1},null, void 0]
al azar entre índices aleatorios. Notará inmediatamente la diferencia. - >> Compruébalo aquí << - .Además de los otros problemas, la sintaxis "for..in" es probablemente más lenta, porque el índice es una cadena, no un entero.
fuente
var i in a
y espere que el índice sea un número entero, entonces hacer algo comoa[i+offset] = <value>
colocar los valores en lugares completamente incorrectos. ("1" + 1 == "11").Un aspecto importante es que
for...in
solo itera sobre las propiedades contenidas en un objeto que tienen su atributo de propiedad enumerable establecido en verdadero. Entonces, si uno intenta iterar sobre un objeto usando, entonces se pueden perder propiedades arbitrarias si su atributo de propiedad enumerable es falso. Es muy posible alterar el atributo de propiedad enumerable para los objetos Array normales para que ciertos elementos no se enumeren. Aunque, en general, los atributos de propiedad tienden a aplicarse a las propiedades de función dentro de un objeto.for...in
Se puede verificar el valor del atributo de propiedad enumerable de una propiedad de la siguiente manera:
O para obtener los cuatro atributos de propiedad:
Esta es una característica disponible en ECMAScript 5: en versiones anteriores no era posible alterar el valor del atributo de propiedad enumerable (siempre se estableció en verdadero).
fuente
El
for
/in
funciona con dos tipos de variables: tablas hash (matrices asociativas) y matrices (no asociativas).JavaScript determinará automáticamente la forma en que pasa a través de los elementos. Entonces, si sabe que su matriz es realmente no asociativa, puede usar
for (var i=0; i<=arrayLen; i++)
y omitir la iteración de detección automática.Pero en mi opinión, es mejor usar
for
/in
, el proceso requerido para esa autodetección es muy pequeño.Una respuesta real para esto dependerá de cómo el navegador analice / interprete el código JavaScript. Puede cambiar entre navegadores.
No puedo pensar en otros propósitos para no usar
for
/in
;fuente
Array
es porqueObject
también lo esfor ... in
trabaja con objetos No existe la autodetección.Porque no iterará sobre las propiedades que pertenecen a los objetos en la cadena del prototipo si no tiene cuidado.
Puede usar
for.. in
, solo asegúrese de verificar cada propiedad con hasOwnProperty .fuente
true
partir de lashasOwnProperty()
verificaciones.isNaN
cheque en cada nombre de propiedad.isNaN
es para verificar si una variable es el valor especial NaN o no, no se puede usar para verificar 'cosas que no sean números' (puede ir con un regular typeof para eso).No es necesariamente malo (en función de lo que está haciendo), pero en el caso de las matrices, si se ha agregado algo
Array.prototype
, obtendrá resultados extraños. Donde esperarías que este ciclo se ejecute tres veces:Si una función llamada
helpfulUtilityMethod
ha sido añadido aArray
'sprototype
, entonces el bucle terminaría corriendo cuatro veces:key
sería0
,1
,2
, yhelpfulUtilityMethod
. Si solo esperabas números enteros, ¡ay!fuente
Debe usar el
for(var x in y)
único en las listas de propiedades, no en los objetos (como se explicó anteriormente).fuente
Usar el
for...in
bucle para una matriz no está mal, aunque puedo adivinar por qué alguien te dijo eso:1.) Ya existe una función o método de orden superior que tiene ese propósito para una matriz, pero tiene más funcionalidad y una sintaxis más simple, llamada 'forEach':
Array.prototype.forEach(function(element, index, array) {} );
2.) Las matrices siempre tienen una longitud, pero
for...in
yforEach
no ejecutan una función para cualquier valor que es'undefined'
, sólo para los índices que tienen un valor definido. Entonces, si solo asigna un valor, estos bucles solo ejecutarán una función una vez, pero dado que se enumera una matriz, siempre tendrá una longitud hasta el índice más alto que tenga un valor definido, pero esa longitud podría pasar desapercibida al usar estos bucles3.) El estándar for loop ejecutará una función tantas veces como usted defina en los parámetros, y dado que una matriz está numerada, tiene más sentido definir cuántas veces desea ejecutar una función. A diferencia de los otros bucles, el bucle for puede ejecutar una función para cada índice de la matriz, ya sea que el valor esté definido o no.
En esencia, puede usar cualquier bucle, pero debe recordar exactamente cómo funcionan. Comprenda las condiciones bajo las cuales los diferentes bucles reiteran, sus funcionalidades separadas, y tenga en cuenta que serán más o menos apropiados para diferentes escenarios.
Además, puede considerarse una mejor práctica usar el
forEach
método que elfor...in
bucle en general, porque es más fácil de escribir y tiene más funcionalidad, por lo que es posible que desee acostumbrarse a usar solo este método y estándar para, pero su llamada.Vea a continuación que los dos primeros bucles solo ejecutan las instrucciones console.log una vez, mientras que el bucle estándar para ejecuta la función tantas veces como se especifique, en este caso, array.length = 6.
fuente
Estas son las razones por las cuales esta (generalmente) es una mala práctica:
for...in
los bucles iteran sobre todas sus propiedades enumerables y las propiedades enumerables de sus prototipos. Por lo general, en una iteración de matriz solo queremos iterar sobre la matriz misma. Y aunque usted mismo no pueda agregar nada a la matriz, sus bibliotecas o marco pueden agregar algo.Ejemplo :
for...in
los bucles no garantizan un orden de iteración específico . Aunque este orden generalmente se ve en la mayoría de los navegadores modernos en estos días, todavía no hay una garantía del 100%.for...in
los bucles ignoran losundefined
elementos de la matriz, es decir, los elementos de la matriz que aún no se han asignado.Ejemplo :
fuente
for ... in es útil cuando se trabaja en un objeto en JavaScript, pero no para un Array, pero aún así no podemos decir que sea una forma incorrecta, pero no se recomienda, mira este ejemplo a continuación usando for ... in loop:
OK, hagámoslo con Array ahora:
Como veis el resultado igual ...
Pero intentemos algo, prototipémonos algo para Array ...
Ahora creamos un nuevo Array ();
Ves a alguien ! ... En realidad, estamos recorriendo un nuevo objeto Array en este caso.
Así que esa es una de las razones por las que debemos usar ... con cuidado, pero no siempre es así ...
fuente
A for ... in loop siempre enumera las claves. Las claves de propiedades de los objetos son siempre cadenas, incluso las propiedades indexadas de una matriz:
fuente
De https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections
fuente
aunque no se aborda específicamente en esta pregunta, agregaría que hay una muy buena razón para no usar para ... en un
NodeList
(como se obtendría de unquerySelectorAll
llamada, ya que no ve los elementos devueltos, en su lugar iterando solo sobre las propiedades NodeList.en el caso de un solo resultado, obtuve:
lo que explicaba por qué mi
for (node in nodes) node.href = newLink;
fallaba.fuente