Lo busqué, pero lo busqué forEach y no solo for. como se dijo, en C # fue un poco diferente, y eso me confundió :)
Dante1986
66
ECMAScript & nbsp; 6 puede contener la construcción "para ... de". Ver para ... de (MDN) para más información. Ya puedes probarlo con versiones recientes de Firefox.
Por el contrario, en Python es más eficiente usar funciones que usar bucles tradicionales. (Considere eso i < leny i++puede hacerlo el motor, en lugar del intérprete.)
joeytwiddle
Respuestas:
7022
TL; DR
No lo use a for-inmenos que lo use con medidas de seguridad o al menos sepa por qué podría morderlo.
Tus mejores apuestas son usualmente
un for-ofbucle (solo ES2015 +),
Array#forEach( spec| MDN) (o sus parientes somey demás) (solo ES5 +),
un simple forbucle pasado de moda ,
o for-incon salvaguardas.
Pero hay mucho más por explorar, sigue leyendo ...
JavaScript tiene una semántica poderosa para recorrer las matrices y los objetos de tipo matriz. He dividido la respuesta en dos partes: opciones para matrices genuinas y opciones para cosas que son simplemente como matrices, como el argumentsobjeto, otros objetos iterables (ES2015 +), colecciones DOM, etc.
Notaré rápidamente que puede usar las opciones de ES2015 ahora , incluso en motores ES5, al trasladar ES2015 a ES5. Busque "Transpiling ES2015" / "Transpiling ES6" para más ...
Bien, veamos nuestras opciones:
Para matrices reales
Tiene tres opciones en ECMAScript 5 ("ES5"), la versión más ampliamente admitida en este momento y dos más agregadas en ECMAScript 2015 ("ES2015", "ES6"):
Uso forEachy relacionados (ES5 +)
Usa un forbucle simple
Usar for-incorrectamente
Usar for-of(usar un iterador implícitamente) (ES2015 +)
Use un iterador explícitamente (ES2015 +)
Detalles:
1. Uso forEachy relacionados
En cualquier entorno vagamente moderno (por lo tanto, no IE8) donde tiene acceso a las Arrayfunciones agregadas por ES5 (directamente o usando polyfills), puede usar forEach( spec| MDN):
var a =["a","b","c"];
a.forEach(function(entry){
console.log(entry);});
forEachacepta una función de devolución de llamada y, opcionalmente, un valor para usar como thiscuando se llama a esa devolución de llamada (no utilizada anteriormente). Se llama a la devolución de llamada para cada entrada en la matriz, en orden, omitiendo las entradas inexistentes en matrices dispersas. Aunque solo utilicé un argumento anterior, la devolución de llamada se llama con tres: el valor de cada entrada, el índice de esa entrada y una referencia a la matriz sobre la que está iterando (en caso de que su función no lo tenga a mano) )
A menos que sea compatible con navegadores obsoletos como IE8 (que NetApps muestra con una participación de mercado de poco más del 4% a partir de este escrito en septiembre de 2016), puede usarlo felizmente forEachen una página web de uso general sin una cuña. Si necesita admitir navegadores obsoletos, el shimming / polyfilling forEachse realiza fácilmente (busque "es5 shim" para ver varias opciones).
forEach tiene el beneficio de que no tiene que declarar las variables de indexación y valor en el ámbito que lo contiene, ya que se proporcionan como argumentos para la función de iteración, y se enfocan tan bien en esa iteración.
Si le preocupa el costo de tiempo de ejecución de realizar una llamada de función para cada entrada de matriz, no se preocupe; detalles .
Además, forEaches la función de "recorrer a través de todos", pero ES5 definió varias otras funciones útiles de "trabajar a través de la matriz y hacer cosas", que incluyen:
every(deja de repetirse la primera vez que vuelve la devolución de llamada falseo algo falsey)
some(deja de repetirse la primera vez que vuelve la devolución de llamada trueo algo verdadero)
filter(crea una nueva matriz que incluye elementos donde regresa la función de filtro truey omite los que regresa false)
map (crea una nueva matriz a partir de los valores devueltos por la devolución de llamada)
reduce (construye un valor llamando repetidamente a la devolución de llamada, pasando valores anteriores; consulte la especificación para obtener detalles; útil para sumar el contenido de una matriz y muchas otras cosas)
reduceRight(como reduce, pero funciona en orden descendente en lugar de ascendente)
2. Use un forbucle simple
A veces las viejas formas son las mejores:
var index;var a =["a","b","c"];for(index =0; index < a.length;++index){
console.log(a[index]);}
Si la longitud de la matriz no cambiará durante el bucle, y es en el código sensibles al rendimiento (poco probable), una versión ligeramente más complicado agarrar la longitud en la delantera podría ser un pequeño poco más rápido:
var index, len;var a =["a","b","c"];for(index =0, len = a.length; index < len;++index){
console.log(a[index]);}
Pero con los motores JavaScript modernos, es raro que necesites sacar ese último jugo.
En ES2015 y superior, puede hacer que sus variables de índice y valor sean locales en el forciclo:
let a =["a","b","c"];for(let index =0; index < a.length;++index){let value = a[index];
console.log(index, value);}//console.log(index); // would cause "ReferenceError: index is not defined"//console.log(value); // would cause "ReferenceError: value is not defined"
let a =["a","b","c"];for(let index =0; index < a.length;++index){let value = a[index];
console.log(index, value);}try{
console.log(index);}catch(e){
console.error(e);// "ReferenceError: index is not defined"}try{
console.log(value);}catch(e){
console.error(e);// "ReferenceError: value is not defined"}
Y cuando haces eso, no solo se recrea valuesino que también indexse recrea para cada iteración del bucle, lo que significa que los cierres creados en el cuerpo del bucle mantienen una referencia al index(y value) creado para esa iteración específica:
let divs = document.querySelectorAll("div");for(let index =0; index < divs.length;++index){
divs[index].addEventListener('click', e =>{
console.log("Index is: "+ index);});}
let divs = document.querySelectorAll("div");for(let index =0; index < divs.length;++index){
divs[index].addEventListener('click', e =>{
console.log("Index is: "+ index);});}
Si tuviera cinco divs, obtendría "Índice es: 0" si hizo clic en el primero e "Índice es: 4" si hizo clic en el último. Esto no funciona si lo usa en varlugar de let.
3. Usar for-incorrectamente
Obtendrá personas que le dicen que use for-in, pero eso no for-ines para lo que sirve . for-inrecorre las propiedades enumerables de un objeto , no los índices de una matriz. El pedido no está garantizado , ni siquiera en ES2015 (ES6). ES2015 + define un orden para las propiedades de los objetos (vía [[OwnPropertyKeys]], [[Enumerate]]y las cosas que los usan como Object.getOwnPropertyKeys), pero no definió que for-inseguiría ese orden; ES2020 lo hizo, sin embargo. (Detalles en esta otra respuesta ).
Los únicos casos de uso reales para for-inuna matriz son:
Está utilizando propiedades que no son elementos y desea incluirlas en el bucle.
Mirando solo ese primer ejemplo: puede usar for-inpara visitar esos elementos de matriz dispersos si usa las salvaguardas apropiadas:
// `a` is a sparse arrayvar key;var a =[];
a[0]="a";
a[10]="b";
a[10000]="c";for(key in a){if(a.hasOwnProperty(key)&&// These checks are/^0$|^[1-9]\d*$/.test(key)&&// explained
key <=4294967294// below){
console.log(a[key]);}}
Que el objeto tiene su propia propiedad con ese nombre (no uno que herede de su prototipo), y
Que la clave son todos los dígitos decimales (p. Ej., Forma de cadena normal, no notación científica), y
Que el valor de la clave cuando se coacciona a un número es <= 2 ^ 32 - 2 (que es 4,294,967,294). ¿De dónde viene ese número? Es parte de la definición de un índice de matriz en la especificación . Otros números (no enteros, números negativos, números mayores que 2 ^ 32 - 2) no son índices de matriz. La razón por la que es 2 ^ 32 - 2 es que eso hace que el mayor valor del índice sea menor que 2 ^ 32 - 1 , que es el valor máximo que lengthpuede tener una matriz . (Por ejemplo, la longitud de una matriz cabe en un entero sin signo de 32 bits). (Apoya a RobG por señalar en un comentario en mi publicación de blog que mi prueba anterior no era del todo correcta).
No harías eso en código en línea, por supuesto. Escribirías una función de utilidad. Quizás:
// Utility function for antiquated environments without `forEach`var hasOwn =Object.prototype.hasOwnProperty;var rexNum =/^0$|^[1-9]\d*$/;function sparseEach(array, callback, thisArg){var index;for(var key in array){
index =+key;if(hasOwn.call(a, key)&&
rexNum.test(key)&&
index <=4294967294){
callback.call(thisArg, array[key], index, array);}}}var a =[];
a[5]="five";
a[10]="ten";
a[100000]="one hundred thousand";
a.b ="bee";
sparseEach(a,function(value, index){
console.log("Value at "+ index +" is "+ value);});
Debajo de las cubiertas, eso obtiene un iterador del conjunto y lo recorre, obteniendo los valores de él. Esto no tiene el problema que for-intiene usar , porque usa un iterador definido por el objeto (la matriz), y las matrices definen que sus iteradores iteran a través de sus entradas (no sus propiedades). A diferencia for-inde ES5, el orden en que se visitan las entradas es el orden numérico de sus índices.
5. Use un iterador explícitamente (ES2015 +)
A veces, es posible que desee utilizar un iterador explícitamente . También puedes hacer eso, aunque es mucho más complicado que for-of. Se parece a esto:
const a =["a","b","c"];const it = a.values();let entry;while(!(entry = it.next()).done){
console.log(entry.value);}
El iterador es un objeto que coincide con la definición de iterador en la especificación. Su nextmétodo devuelve un nuevo objeto de resultado cada vez que lo llama. El objeto resultante tiene una propiedad doneque nos dice si está hecho y una propiedad valuecon el valor para esa iteración. ( donees opcional si lo fuera false, valuees opcional si lo fuera undefined).
El significado de valuevaría según el iterador; Las matrices admiten (al menos) tres funciones que devuelven iteradores:
values(): Este es el que usé arriba. Se devuelve un iterador que cada valuees la entrada de la matriz para esa iteración ( "a", "b"y "c"en el ejemplo anterior).
keys(): Devuelve un iterador donde cada uno valuees la clave para esa iteración (por lo que para nuestro aanterior, sería "0", entonces "1", entonces "2").
entries(): Devuelve un iterador donde cada uno valuees una matriz en el formulario [key, value]para esa iteración.
Para objetos tipo matriz
Además de las matrices verdaderas, también hay objetos en forma de matriz que tienen una lengthpropiedad y propiedades con nombres numéricos: NodeListinstancias, el argumentsobjeto, etc. ¿Cómo recorremos sus contenidos?
Use cualquiera de las opciones anteriores para matrices
Al menos algunos, y posiblemente la mayoría o incluso todos, los enfoques de matriz anteriores se aplican con frecuencia igualmente bien a objetos similares a una matriz:
Uso forEachy relacionados (ES5 +)
Las diversas funciones en Array.prototypeson "intencionalmente genéricas" y, por lo general, se pueden usar en objetos tipo matriz a través de Function#callo Function#apply. (Consulte la Advertencia para los objetos proporcionados por el host al final de esta respuesta, pero es un problema poco frecuente).
Suponga que desea utilizar forEachen una Node's childNodespropiedad. Harías esto:
Array.prototype.forEach.call(node.childNodes,function(child){// Do something with `child`});
Si va a hacer eso mucho, es posible que desee obtener una copia de la referencia de función en una variable para su reutilización, por ejemplo:
// (This is all presumably in some scoping function)var forEach =Array.prototype.forEach;// Then later...
forEach.call(node.childNodes,function(child){// Do something with `child`});
Usa un forbucle simple
Obviamente, un forbucle simple se aplica a objetos tipo matriz.
Usar for-incorrectamente
for-incon las mismas garantías que con una matriz, también debería funcionar con objetos similares a una matriz; se puede aplicar la advertencia para los objetos proporcionados por el host en el n. ° 1 anterior.
Usar for-of(usar un iterador implícitamente) (ES2015 +)
for-ofusa el iterador proporcionado por el objeto (si lo hay). Eso incluye objetos proporcionados por el host. Por ejemplo, la especificación para NodeListfrom querySelectorAllse actualizó para admitir la iteración. La especificación para el HTMLCollectionde getElementsByTagNameno era.
Use un iterador explícitamente (ES2015 +)
Ver # 4.
Crea una verdadera matriz
Otras veces, es posible que desee convertir un objeto tipo matriz en una matriz verdadera. Hacer eso es sorprendentemente fácil:
Usa el slicemétodo de matrices
Podemos usar el slicemétodo de matrices, que al igual que los otros métodos mencionados anteriormente es "intencionalmente genérico" y, por lo tanto, puede usarse con objetos similares a una matriz, como este:
var trueArray =Array.prototype.slice.call(arrayLikeObject);
Entonces, por ejemplo, si queremos convertir a NodeListen una verdadera matriz, podríamos hacer esto:
var divs =Array.prototype.slice.call(document.querySelectorAll("div"));
Vea la Advertencia para los objetos proporcionados por el host a continuación. En particular, tenga en cuenta que esto fallará en IE8 y versiones anteriores, lo que no le permite usar objetos proporcionados por el host de thisesa manera.
Usar sintaxis de propagación ( ...)
También es posible usar la sintaxis extendida de ES2015 con motores JavaScript que admiten esta función. Como for-of, esto usa el iterador proporcionado por el objeto (ver # 4 en la sección anterior):
var trueArray =[...iterableObject];
Entonces, por ejemplo, si queremos convertir una NodeListmatriz verdadera, con sintaxis extendida esto se vuelve bastante sucinto:
var divs =[...document.querySelectorAll("div")];
Utilizar Array.from
Array.from(especificación) | (MDN) (ES2015 +, pero fácilmente rellenado) crea una matriz a partir de un objeto similar a una matriz, opcionalmente pasando primero las entradas a través de una función de mapeo. Entonces:
var divs =Array.from(document.querySelectorAll("div"));
O si desea obtener una matriz de nombres de etiquetas de los elementos con una clase determinada, usaría la función de mapeo:
// Arrow function (ES2015):var divs =Array.from(document.querySelectorAll(".some-class"), element => element.tagName);// Standard function (since `Array.from` can be shimmed):var divs =Array.from(document.querySelectorAll(".some-class"),function(element){return element.tagName;});
Advertencia para objetos proporcionados por el host
Si usa Array.prototypefunciones con objetos de tipo matriz proporcionados por el host (listas DOM y otras cosas proporcionadas por el navegador en lugar del motor de JavaScript), debe asegurarse de realizar pruebas en sus entornos de destino para asegurarse de que el objeto proporcionado por el host se comporta correctamente . La mayoría se comporta correctamente (ahora), pero es importante realizar una prueba. La razón es que la mayoría de los Array.prototypemétodos que es probable que desee utilizar se basan en el objeto proporcionado por el host que da una respuesta honesta a la [[HasProperty]]operación abstracta . Al escribir estas líneas, los navegadores hacen un muy buen trabajo de esto, pero la especificación 5.1 permitió la posibilidad de que un objeto proporcionado por el host no sea honesto. Está en §8.6.2 , varios párrafos debajo de la gran mesa cerca del comienzo de esa sección), donde dice:
Los objetos host pueden implementar estos métodos internos de cualquier manera a menos que se especifique lo contrario; Por ejemplo, una posibilidad es que [[Get]]y [[Put]]para un objeto host particular, de hecho, obtenga y almacene valores de propiedad, pero [[HasProperty]]siempre genera falso .
(No pude encontrar la verborrea equivalente en la especificación ES2015, pero está obligado a seguir siendo el caso.) Una vez más, a partir de este escrito el host proporcionado por el arreglo de objetos similares en los navegadores modernos [común NodeListde los casos, por ejemplo] hacer mango [[HasProperty]]correctamente, pero es importante hacer la prueba).
También me gustaría agregar que .forEachno se puede romper de manera eficiente. Tienes que lanzar una excepción para realizar el descanso.
Pijusn
82
@Pius: si quieres romper el ciclo, puedes usarlo some. (Hubiera preferido permitir el descanso forEachtambién, pero, um, no me preguntaron. ;-))
TJ Crowder
66
@TJCrowder Es cierto, a pesar de que se parece más a una solución, ya que no es su propósito principal.
Pijusn
8
@ user889030: necesita un ,después k=0, no un ;. Recuerde, la programación es muchas cosas, una de las cuales es prestar mucha atención a los detalles ... :-)
TJ Crowder
55
@ JimB: Eso está cubierto anteriormente (y lengthno es un método). :-)
TJ Crowder
513
Nota : Esta respuesta está irremediablemente desactualizada. Para un enfoque más moderno, mire los métodos disponibles en una matriz . Los métodos de interés pueden ser:
para cada
mapa
filtrar
Código Postal
reducir
cada
algunos
La forma estándar de iterar una matriz en JavaScript es un forbucle de vainilla :
var length = arr.length,
element =null;for(var i =0; i < length; i++){
element = arr[i];// Do something with element}
Sin embargo, tenga en cuenta que este enfoque solo es bueno si tiene una matriz densa y cada índice está ocupado por un elemento. Si la matriz es escasa, entonces puede encontrar problemas de rendimiento con este enfoque, ya que iterará sobre muchos índices que realmente no existen en la matriz. En este caso, un for .. inbucle podría ser una mejor idea. Sin embargo , debe usar las salvaguardas apropiadas para garantizar que solo se actúen las propiedades deseadas de la matriz (es decir, los elementos de la matriz), ya que el for..inbucle también se enumerará en los navegadores heredados, o si las propiedades adicionales se definen como enumerable.
En ECMAScript 5 habrá un método forEach en el prototipo de matriz, pero no es compatible con los navegadores heredados. Por lo tanto, para poder usarlo de manera consistente, debe tener un entorno que lo admita (por ejemplo, Node.js para JavaScript del lado del servidor) o usar un "Polyfill". Sin embargo, el Polyfill para esta funcionalidad es trivial y, dado que hace que el código sea más fácil de leer, es un buen polyfill para incluir.
¿Por qué for(instance in objArray) no es un uso correcto? me parece más simple, pero escucho que hablas de que no es una forma correcta de uso.
Dante1986
21
Puede usar el almacenamiento en caché de longitud en línea: for (var i = 0, l = arr.length; i <l; i ++)
Robert Hoffmann
3
¿La coma al final de la primera línea es intencional, o es un error tipográfico (podría ser punto y coma)?
Mohd Abdul Mujib
66
@ wardha-Web Es intencional. Nos permite declarar múltiples variables con una sola varpalabra clave. Si hubiéramos usado un punto y coma, entonces elementhabría sido declarado en el ámbito global (o, más bien, JSHint nos habría gritado antes de que llegara a producción).
Probablemente voy a usar esta respuesta con la mayor frecuencia. No es la mejor respuesta a la pregunta, pero en la práctica será la más simple y más aplicable para aquellos de nosotros que usamos jQuery. Sin embargo, creo que todos deberíamos aprender el estilo vainilla. Nunca está de más ampliar tu comprensión.
mopsyd
47
Solo por el simple hecho de que jQuery es mucho más lento que las soluciones nativas. JQuery recomienda utilizar JavaScript nativo en lugar de jQuery siempre que sea posible. jsperf.com/browser-diet-jquery-each-vs-for-loop
Kevin Boss
8
Abstenerse de usar jQuery cuando puede usar vanilla js
Noe
2
Palo de la norma JS, mantener las bibliotecas 3 ª parte fuera de la respuesta a menos que no es una solución idioma nativo
scubasteve
116
Bucle hacia atrás
Creo que el reverso de loop merece una mención aquí:
for(var i = array.length; i--;){// process array[i]}
Ventajas:
No es necesario declarar una lenvariable temporal ni comparar array.lengthen cada iteración, ya que cualquiera de las dos podría ser una optimización por minuto.
Eliminar hermanos del DOM en orden inverso suele ser más eficiente . (El navegador necesita hacer menos desplazamiento de elementos en sus matrices internas).
Si modifica la matriz mientras realiza un bucle, en o después del índice i (por ejemplo, elimina o inserta un elemento en array[i]), entonces un bucle hacia adelante omitirá el elemento que se desplazó a la izquierda a la posición i , o volverá a procesar el ítem i . desplazado a la derecha. En un bucle for tradicional, puede actualizar i para señalar el siguiente elemento que necesita procesamiento - 1, pero simplemente invertir la dirección de la iteración suele ser una solución más simple y elegante .
Del mismo modo, al modificar o eliminar elementos DOM anidados , el procesamiento inverso puede evitar errores . Por ejemplo, considere modificar el innerHTML de un nodo padre antes de manejar sus hijos. Cuando se llegue al nodo secundario, se separará del DOM y habrá sido reemplazado por un elemento secundario recién creado cuando se escribió innerHTML del elemento primario.
Es más corto de escribir y leer que algunas de las otras opciones disponibles. Aunque pierde con forEach()y para ES6 for ... of.
Desventajas
Procesa los artículos en orden inverso. Si estaba creando una nueva matriz a partir de los resultados, o imprimiendo cosas en la pantalla, naturalmente, la salida se invertirá con respecto al orden original.
Insertar hermanos repetidamente en el DOM como primer hijo para retener su orden es menos eficiente . (El navegador seguiría teniendo que cambiar las cosas correctamente). Para crear nodos DOM de manera eficiente y en orden, simplemente realice un bucle hacia adelante y agregue de forma normal (y también use un "fragmento de documento").
El bucle inverso es confuso para los desarrolladores junior. (Puede considerar eso una ventaja, dependiendo de su perspectiva).
¿Debo usarlo siempre?
Algunos desarrolladores usan el bucle inverso para de forma predeterminada , a menos que haya una buena razón para avanzar.
Aunque las ganancias de rendimiento generalmente son insignificantes, grita:
"Simplemente haga esto a cada elemento de la lista, ¡no me importa el pedido!"
Sin embargo, en la práctica eso no es en realidad una indicación confiable de intención, ya que es indistinguible de aquellas ocasiones en las que te importa el orden y realmente necesitas hacer un ciclo en reversa. Entonces, de hecho, se necesitaría otra construcción para expresar con precisión la intención de "no me importa", algo que actualmente no está disponible en la mayoría de los idiomas, incluido ECMAScript, pero que podría llamarse, por ejemplo,forEachUnordered() ,.
Si el orden no importa, y la eficiencia es una preocupación (en el bucle más interno de un juego o motor de animación), entonces puede ser aceptable usar el bucle inverso para su patrón de inicio. Solo recuerde que ver un bucle inverso para en el código existente no significa necesariamente que el orden sea irrelevante.
Era mejor usar forEach ()
En general, para el código de nivel superior donde la claridad y la seguridad son mayores preocupaciones, anteriormente recomendé usarlo Array::forEachcomo patrón predeterminado para el bucle (aunque en estos días prefiero usarlo for..of). Las razones para preferir forEachsobre un bucle inverso son:
Es más claro de leer.
Indica que i no va a ser desplazado dentro del bloque (que es siempre un posible escondite sorpresa en tiempo fory whilebucles).
Le da un alcance libre para cierres.
Reduce la fuga de variables locales y la colisión accidental con (y la mutación de) variables externas.
Luego, cuando vea el bucle inverso para su código, es una pista de que se invierte por una buena razón (tal vez una de las razones descritas anteriormente). Y ver un bucle de avance for tradicional puede indicar que puede tener lugar un cambio.
(Si la discusión sobre la intención no tiene sentido para usted, entonces usted y su código pueden beneficiarse al ver la conferencia de Crockford sobre Estilo de programación y su cerebro ).
Ahora es incluso mejor usarlo para ... ¡de!
Existe un debate sobre si es preferible for..ofo forEach()no:
Para obtener la máxima compatibilidad con el navegador, se for..ofrequiere un polyfill para los iteradores, lo que hace que su aplicación sea un poco más lenta de ejecutar y un poco más grande de descarga.
Personalmente, tiendo a usar lo que parece más fácil de leer, a menos que el rendimiento o la minificación se hayan convertido en una preocupación importante. Así que en estos días yo prefiero usar for..ofen lugar de forEach(), pero voy a utilizar siempre mapo filtero findo somecuando sea aplicable. (Por el bien de mis colegas, rara vez uso reduce).
¿Como funciona?
for(var i =0; i < array.length; i++){...}// Forwardsfor(var i = array.length; i--;){...}// Reverse
Notarás que i--es la cláusula central (donde generalmente vemos una comparación) y la última cláusula está vacía (donde generalmente vemos i++). Eso significa que i--también se usa como condición para la continuación. Crucialmente, se ejecuta y se verifica antes de cada iteración.
¿Cómo puede comenzar array.lengthsin explotar?
Debido a que se i--ejecuta antes de cada iteración, en la primera iteración realmente tendremos acceso al elemento en el array.length - 1que evita cualquier problema con los elementos fuera de los límites de la matrizundefined .
¿Por qué no deja de iterar antes del índice 0?
El ciclo dejará de iterar cuando la condición se i--evalúe como un valor falsey (cuando produce 0).
El truco es que --i, a diferencia , el i--operador final disminuye ipero produce el valor antes de la disminución. Su consola puede demostrar esto:
> var i = 5; [i, i--, i];
[5, 5, 4]
Así que en la iteración final, i estaba anteriormente 1 y la i--expresión cambia a 0 , pero en realidad el rendimiento de 1 (Truthy), y así la condición pasa. En la siguiente iteración i--cambia de i a -1 pero produce 0 (falsey), lo que hace que la ejecución se salga inmediatamente del fondo del bucle.
En el tradicional for for loop, i++y ++ison intercambiables (como señala Douglas Crockford). Sin embargo, en el reverso del bucle for, dado que nuestro decremento también es nuestra expresión de condición, debemos seguir i--si queremos procesar el elemento en el índice 0.
Trivialidades
A algunas personas les gusta dibujar una pequeña flecha en el forbucle inverso y terminar con un guiño:
for(var i = array.length; i -->0;){
Los créditos van a WYL por mostrarme los beneficios y los horrores del bucle inverso.
Olvidé agregar los puntos de referencia . También olvidé mencionar que el bucle inverso es una optimización significativa en procesadores de 8 bits como el 6502, ¡donde realmente obtienes la comparación gratis!
joeytwiddle
La misma respuesta se da de manera mucho más concisa aquí (en una pregunta diferente).
var index,
value;for(index in obj){
value = obj[index];}
Hay una trampa. for..inrecorrerá cada uno de los miembros enumerables del objeto y los miembros de su prototipo. Para evitar leer valores que se heredan a través del prototipo del objeto, simplemente verifique si la propiedad pertenece al objeto:
for(i in obj){if(obj.hasOwnProperty(i)){//do stuff}}
Además, ECMAScript 5 ha agregado un forEachmétodo Array.prototypeque se puede usar para enumerar sobre una matriz usando un calback (el polyfill está en los documentos, por lo que aún puede usarlo para navegadores más antiguos):
Es importante tener en cuenta que Array.prototype.forEachno se rompe cuando vuelve la devolución de llamada false. jQuery y Underscore.js proporcionan sus propias variaciones eachpara proporcionar bucles que se pueden cortocircuitar.
Entonces, ¿cómo se puede salir de un bucle foreach ECMAScript5 como lo haríamos para un bucle normal o un bucle foreach como el que se encuentra en los lenguajes de estilo C?
Ciaran Gallagher
55
@CiaranG, en JavaScript es común ver eachmétodos que permiten return falseser utilizados para salir del ciclo, pero con forEachesto no es una opción. Se podría usar un indicador externo (es decir if (flag) return;, pero solo evitaría que el resto del cuerpo de la función se ejecute, forEachseguiría iterando en toda la colección.
ZzzzBov
43
Si desea realizar un bucle sobre una matriz, use el forbucle estándar de tres partes .
for(var i =0; i < myArray.length; i++){var arrayItem = myArray[i];}
Puede obtener algunas optimizaciones de rendimiento al almacenar en caché myArray.lengtho iterar al revés.
para (var i = 0, length = myArray.length; i <length; i ++) debería hacerlo
Edson Medina
55
@EdsonMedina Eso también creará una nueva variable global llamada length. ;)
joeytwiddle
44
@joeytwiddle Sí, pero eso está más allá del alcance de esta publicación. Creará una variable global i de todos modos.
Edson Medina
66
@EdsonMedina Mis disculpas, me equivoqué completamente. Usar ,después de una tarea no introduce un nuevo global, por lo que su sugerencia está bien . Estaba confundiendo esto por un problema diferente: usar =después de una asignación crea un nuevo global.
joeytwiddle
Cuidado con la variable i no es local para el bucle. JavaScript no tiene alcance de bloque. Probablemente sea mejor declarar var i, length, arrayItem;antes del bucle para evitar este malentendido.
James
35
Sé que esta es una publicación antigua, y ya hay muchas respuestas geniales. Para un poco más de integridad, pensé que lanzaría otro usando AngularJS . Por supuesto, esto solo se aplica si está usando Angular, obviamente, sin embargo, me gustaría ponerlo de todos modos.
angular.forEachtoma 2 argumentos y un tercer argumento opcional. El primer argumento es el objeto (matriz) para iterar, el segundo argumento es la función iteradora, y el tercer argumento opcional es el contexto del objeto (básicamente denominado dentro del bucle como 'esto'.
Hay diferentes formas de usar el bucle forEach de angular. El más simple y probablemente el más utilizado es
var temp =[1,2,3];
angular.forEach(temp,function(item){//item will be each element in the array//do something});
Otra forma útil para copiar elementos de una matriz a otra es
var temp =[1,2,3];var temp2 =[];
angular.forEach(temp,function(item){this.push(item);//"this" refers to the array passed into the optional third parameter so, in this case, temp2.}, temp2);
Sin embargo, no tiene que hacer eso, simplemente puede hacer lo siguiente y es equivalente al ejemplo anterior:
Ahora hay ventajas y desventajas de usar el angular.forEach función en lugar del forbucle incorporado con sabor a vainilla .
Pros
Legibilidad fácil
Fácil escritura
Si está disponible, angular.forEachusará el ES5 para cada bucle. Ahora, llegaré a la eficiencia en la sección contras, ya que los bucles forEach son mucho más lentos que los bucles for. Menciono esto como un profesional porque es bueno ser consistente y estandarizado.
Considere los siguientes 2 bucles anidados, que hacen exactamente lo mismo. Digamos que tenemos 2 matrices de objetos y cada objeto contiene una matriz de resultados, cada uno de los cuales tiene una propiedad Value que es una cadena (o lo que sea). Y digamos que necesitamos iterar sobre cada uno de los resultados y si son iguales, entonces realice alguna acción:
angular.forEach(obj1.results,function(result1){
angular.forEach(obj2.results,function(result2){if(result1.Value=== result2.Value){//do something}});});//exact same with a for loopfor(var i =0; i < obj1.results.length; i++){for(var j =0; j < obj2.results.length; j++){if(obj1.results[i].Value=== obj2.results[j].Value){//do something}}}
De acuerdo, este es un ejemplo hipotético muy simple, pero he escrito triple incrustado para bucles utilizando el segundo enfoque y fue muy difícil de leer y escribir.
Contras
Eficiencia. angular.forEach, y los nativos forEach, para el caso, son mucho más lentos que el forciclo normal ... aproximadamente un 90% más lento . Por lo tanto, para conjuntos de datos grandes, es mejor atenerse al forciclo nativo .
Sin descanso, continuar o devolver el apoyo. continueen realidad está respaldado por " accidente ", para continuar en un angular.forEachsimple poner una return;declaración en la función como angular.forEach(array, function(item) { if (someConditionIsTrue) return; });que hará que continúe fuera de la función para esa iteración. Esto también se debe al hecho de que el nativoforEach no admite interrupción o continuación tampoco.
Estoy seguro de que también hay otros pros y contras, y siéntase libre de agregar cualquiera que considere conveniente. Creo que, en resumen, si necesita eficiencia, quédese solo con el forbucle nativo para sus necesidades de bucle. Pero, si sus conjuntos de datos son más pequeños y se puede renunciar a una cierta eficiencia a cambio de legibilidad y capacidad de escritura, entonces de todos modos arroje angular.forEacha ese chico malo.
function forEach(list,callback){var length = list.length;for(var n =0; n < length; n++){
callback.call(list[n]);}}var myArray =['hello','world'];
forEach(
myArray,function(){
alert(this);// do something});
Probablemente el for(i = 0; i < array.length; i++)bucle no sea la mejor opción. ¿Por qué? Si tienes esto:
var array =newArray();
array[1]="Hello";
array[7]="World";
array[11]="!";
El método llamará de array[0]a array[2]. Primero, esto primero hará referencia a variables que ni siquiera tiene, segundo no tendría las variables en la matriz, y tercero esto hará que el código sea más audaz. Mira aquí, es lo que uso:
for(var i in array){var el = array[i];//If you want 'i' to be INT just put parseInt(i)//Do something with el}
Y si quieres que sea una función, puedes hacer esto:
function foreach(array, call){for(var i in array){
call(array[i]);}}
Si quieres romper, un poco más de lógica:
function foreach(array, call){for(var i in array){if(call(array[i])==false){break;}}}
Hay tres implementaciones de foreachen jQuery de la siguiente manera.
var a =[3,2];
$(a).each(function(){console.log(this.valueOf())});//Method 1
$.each(a,function(){console.log(this.valueOf())});//Method 2
$.each($(a),function(){console.log(this.valueOf())});//Method 3
Donde ofevita las rarezas asociadas iny hace que funcione como el forbucle de cualquier otro lenguaje, y se letune identro del bucle en lugar de dentro de la función.
Las llaves ( {}) se pueden omitir cuando solo hay un comando (por ejemplo, en el ejemplo anterior).
Una solución fácil ahora sería usar la biblioteca underscore.js . Proporciona muchas herramientas útiles, como eachy delegará automáticamente el trabajo al nativo forEachsi está disponible.
No hay ningún for eachbucle en JavaScript nativo . Puede usar bibliotecas para obtener esta funcionalidad (recomiendo Underscore.js ), use un forbucle simple .
Este es un iterador para una lista NO dispersa donde el índice comienza en 0, que es el escenario típico cuando se trata de document.getElementsByTagName o document.querySelectorAll)
function each( fn, data ){if(typeof fn =='string')eval('fn = function(data, i){'+ fn +'}');for(var i=0, L=this.length; i < L; i++)
fn.call(this[i], data, i );returnthis;}Array.prototype.each = each;
Ejemplos de uso:
Ejemplo 1
var arr =[];[1,2,3].each(function(a){ a.push(this*this}, arr);
arr =[1,4,9]
each.call(document.getElementsByTagName('p'),"if( i % 2 == 0) this.className = data;",'red');
Cualquier otra etiqueta p obtiene class="red">
Ejemplo # 4
each.call(document.querySelectorAll('p.blue'),function(newClass, i){if( i <20)this.className = newClass;},'green');
Y finalmente las primeras 20 etiquetas p azules se cambian a verde
Precaución al usar una cadena como función: la función se crea fuera de contexto y debe usarse solo cuando esté seguro del alcance variable. De lo contrario, es mejor pasar funciones donde el alcance es más intuitivo.
Hay algunas formas de recorrer una matriz en JavaScript, como se muestra a continuación:
para - es el más común . Bloque completo de código para bucle
var languages =["Java","JavaScript","C#","Python"];var i, len, text;for(i =0, len = languages.length, text =""; i < len; i++){
text += languages[i]+"<br>";}
document.getElementById("example").innerHTML = text;
Bucles funcionales - forEach, map, filter, también reduce(que bucle a través de la función, pero se utilizan si hay que hacer algo con su matriz, etc.
// For example, in this case we loop through the number and double them up using the map functionvar numbers =[65,44,12,4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num *2});
Pequeña corrección: forEachno es un bucle "funcional" ya que no devuelve uno nuevo Array(en realidad no devuelve nada), solo itera.
nicholaswmin
19
ECMAScript 5 (la versión en JavaScript) para trabajar con matrices:
forEach : repite cada elemento de la matriz y hace lo que sea necesario con cada elemento.
['C','D','E'].forEach(function(element, index){
console.log(element +" is #"+(index+1)+" in the musical scale");});// Output// C is the #1 in musical scale// D is the #2 in musical scale// E is the #3 in musical scale
En el caso, más interesado en la operación en matriz utilizando alguna característica incorporada.
map : crea una nueva matriz con el resultado de la función de devolución de llamada. Este método es bueno para usarse cuando necesita formatear los elementos de su matriz.
// Let's upper case the items in the array['bob','joe','jen'].map(function(elem){return elem.toUpperCase();});// Output: ['BOB', 'JOE', 'JEN']
reducir : como su nombre lo indica, reduce la matriz a un solo valor llamando a la función dada que pasa en el elemento actual y el resultado de la ejecución anterior.
No hay capacidad incorporada para entrar forEach. Para interrumpir la ejecución, use lo Array#somesiguiente:
[1,2,3].some(function(number){return number ===1;});
Esto funciona porque somedevuelve verdadero tan pronto como cualquiera de las devoluciones de llamada, ejecutadas en orden de matriz, devuelve verdadero, cortocircuitando la ejecución del resto.
Respuesta original
ver prototipo de matriz para algunos
También me gustaría agregar esto como una composición de un bucle inverso y una respuesta anterior para alguien a quien también le gustaría esta sintaxis.
var foo =[object,object,object];for(var i = foo.length, item; item = foo[--i];){
console.log(item);}
Pros:
El beneficio para esto: ya tiene la referencia en el primero, así no será necesario declararla más adelante con otra línea. Es útil al recorrer en bucle la matriz de objetos.
Contras:
Esto se romperá siempre que la referencia sea falsa: falsey (indefinida, etc.). Sin embargo, se puede usar como una ventaja. Sin embargo, sería un poco más difícil de leer. Y también, dependiendo del navegador, puede "no" estar optimizado para funcionar más rápido que el original.
La desestructuración y el uso del operador de propagación han demostrado ser bastante útiles para los recién llegados a ECMAScript 6 por ser más legibles / estéticos, aunque algunos veteranos de JavaScript podrían considerarlo desordenado. Juniors o algunas otras personas pueden encontrarlo útil.
Los siguientes ejemplos utilizarán la for...ofdeclaración y el .forEachmétodo.
Ejemplos 6, 7 y 8 se pueden utilizar con cualquier bucles funcionales como .map, .filter, .reduce, .sort, .every, .some. Para obtener más información sobre estos métodos, consulte el objeto Array .
Ejemplo 1:for...of bucle normal : no hay trucos aquí.
let arrSimple =['a','b','c'];for(let letter of arrSimple){
console.log(letter);}
let arrFruits =['apple','orange','banana'];for(let[firstLetter,...restOfTheWord]of arrFruits){// Create a shallow copy using the spread operatorlet[lastLetter]=[...restOfTheWord].reverse();
console.log(firstLetter, lastLetter, restOfTheWord);}
// let arrSimple = ['a', 'b', 'c'];// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`// this example will use a multi-dimensional array of the following format type:// `arrWithIndex: [number, string][]`let arrWithIndex =[[0,'a'],[1,'b'],[2,'c'],];// Same thing can be achieved using `.map` method// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);// Same thing can be achieved using `Object.entries`// NOTE: `Object.entries` method doesn't work on Internet Explorer unless it's polyfilled// let arrWithIndex = Object.entries(arrSimple);for(let[key, value]of arrWithIndex){
console.log(key, value);}
let arrWithIndex =[[0,'a'],[1,'b'],[2,'c'],];// Not to be confused here, `forEachIndex` is the real index// `mappedIndex` was created by "another user", so you can't really trust it
arrWithIndex.forEach(([mappedIndex, item], forEachIndex)=>{
console.log(forEachIndex, mappedIndex, item);});
let arrWithObjects =[{
name:'Jon',
age:32},{
name:'Elise',
age:33}];// NOTE: Destructuring objects while using shorthand functions// are required to be surrounded by parentheses
arrWithObjects.forEach(({ name, age: aliasForAge })=>{
console.log(name, aliasForAge)});
Una forma más cercana a su idea sería usar una Array.forEach()que acepte una función de cierre que se ejecutará para cada elemento de la matriz.
myArray.forEach((item)=>{// Do something
console.log(item);});
Otra forma viable sería usar el Array.map()que funciona de la misma manera, pero también toma todos los valores que devuelve y los devuelve en una nueva matriz (esencialmente asignando cada elemento a uno nuevo), de esta manera:
Esto está mal, mapno muta los elementos de la matriz, porque devuelve una nueva matriz, siendo los elementos de esa nueva el resultado de aplicar la función a los elementos de la matriz anterior.
Jesús Franco
Nunca dije que no devuelve una nueva matriz, me refería al cambio aplicado por la función. Pero aquí lo cambiaré en la respuesta.
Ante Jablan Adamović
de nuevo mal, el mapa no modifica ni muta en todos los elementos de la matriz original, he propuesto y edito la respuesta enfatizando que el mapa funciona con una copia de los elementos originales, dejando la matriz original intacta
Jesús Franco
7
Puedes llamar a cada uno de estos:
forEachiterará sobre la matriz que proporcione y para cada iteración tendrá elementel valor de esa iteración. Si necesita un índice, puede obtener el índice actual pasando iel segundo parámetro en la función de devolución de llamada para forEach.
Foreach es básicamente una función de orden superior, que toma otra función como parámetro.
let theArray=[1,3,2];
theArray.forEach((element)=>{// Use the element of the array
console.log(element)}
Salida:
132
También puede iterar sobre una matriz como esta:
for(let i=0; i<theArray.length; i++){
console.log(i);// i will have the value of each index}
Si desea recorrer un conjunto de objetos con la función de flecha:
let arr =[{name:'john', age:50},{name:'clark', age:19},{name:'mohan', age:26}];
arr.forEach((person)=>{
console.log('I am '+ person.name +' and I am '+ person.age +' old');})
La sintaxis lambda no suele funcionar en Internet Explorer 10 o inferior.
Usualmente uso el
[].forEach.call(arrayName,function(value,index){
console.log("value of the looped element"+ value);
console.log("index of the looped element"+ index);});
Si eres un fanático de jQuery y ya tienes un archivo jQuery en ejecución, debes invertir las posiciones de los parámetros de índice y valor
$("#ul>li").each(function(**index, value**){
console.log("value of the looped element"+ value);
console.log("index of the looped element"+ index);});
Si tiene una matriz masiva que debe usar iteratorspara ganar algo de eficiencia. Los iteradores son una propiedad de ciertas colecciones de JavaScript (como Map, Set, String, Array). Incluso, for..ofutiliza iteratordebajo del capó.
Los iteradores mejoran la eficiencia al permitirle consumir los elementos en una lista uno a la vez como si fueran una secuencia. Lo que hace que un iterador sea especial es cómo atraviesa una colección. Otros bucles necesitan cargar toda la colección por adelantado para iterar sobre ella, mientras que un iterador solo necesita conocer la posición actual en la colección.
Accede al elemento actual llamando al nextmétodo del iterador . El siguiente método devolverá el valuedel elemento actual y una booleanpara indicar cuándo ha llegado al final de la colección. El siguiente es un ejemplo de creación de un iterador a partir de una matriz.
Transforme su matriz regular en iterador usando un values()método como este:
const myArr =[2,3,4]let it = myArr.values();
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
Hoy (18/12/2019) realizo prueba en mi v10.13.6 macOS (High Sierra), en Chrome v 79.0, v13.0.4 Safari y Firefox v71.0 (64 bits) - Conclusiones sobre la optimización (y micro-optimización de los cuales generalmente no vale la pena introducirlo en el código porque el beneficio es pequeño, pero la complejidad del código crece).
Parece que el tradicional for i( Aa ) es una buena opción para escribir código rápido en todos los navegadores.
Las otras soluciones, como for-of( Ad ), todas en el grupo C. ... suelen ser de 2 a 10 (y más) veces más lentas que Aa , pero para arreglos pequeños está bien usarlo, en aras de aumentar la claridad del código.
Los bucles con longitud de matriz en caché n( Ab, Bb, Be ) son a veces más rápidos, a veces no. Probablemente los compiladores detectan automáticamente esta situación e introducen el almacenamiento en caché. Las diferencias de velocidad entre las versiones en caché y no en caché ( Aa, Ba, Bd ) son de aproximadamente ~ 1%, por lo que parece que introducir nes una microoptimización .
Las i--soluciones similares en las que el bucle comienza desde el último elemento de matriz ( Ac, Bc ) suelen ser ~ 30% más lentas que las soluciones directas; probablemente la razón sea la forma en que funciona la memoria caché de la CPU : la lectura de memoria directa es más óptima para el almacenamiento en caché de la CPU). Se recomienda NO UTILIZAR tales soluciones.
Detalles
En las pruebas calculamos la suma de los elementos de la matriz. Realizo una prueba para matrices pequeñas (10 elementos) y matrices grandes (elementos 1M) y las divido en tres grupos:
Al iterar sobre una matriz, a menudo queremos lograr uno de los siguientes objetivos:
Queremos iterar sobre la matriz y crear una nueva matriz:
Array.prototype.map
Queremos iterar sobre la matriz y no crear una nueva matriz:
Array.prototype.forEach
for..oflazo
En JavaScript, hay muchas formas de lograr ambos objetivos. Sin embargo, algunos son más convenientes que otros. A continuación puede encontrar algunos métodos de uso común (la IMO más conveniente) para lograr la iteración de matriz en JavaScript.
Crear nueva matriz: Map
map()es una función ubicada en la Array.prototypeque puede transformar cada elemento de una matriz y luego devuelve una nueva matriz. map()toma como argumento una función de devolución de llamada y funciona de la siguiente manera:
let arr =[1,2,3,4,5];let newArr = arr.map((element, index, array)=>{return element *2;})
console.log(arr);
console.log(newArr);
La devolución de llamada que hemos pasado map()como argumento se ejecuta para cada elemento. Luego se devuelve una matriz que tiene la misma longitud que la matriz original. En este nuevo elemento de matriz se transforma mediante la función de devolución de llamada que se pasa como argumento paramap() .
La diferencia distintiva entre mapy otro mecanismo de bucle como forEachy un for..ofbucle es que mapdevuelve una nueva matriz y deja intacta la matriz anterior (excepto si la manipula explícitamente con think like splice).
Además, tenga en cuenta que la mapdevolución de llamada de la función proporciona el número de índice de la iteración actual como un segundo argumento. Además, ¿el tercer argumento proporciona la matriz en la que mapse llamó? Algunas veces estas propiedades pueden ser muy útiles.
Loop usando forEach
forEaches una función en la Array.prototypeque se toma una función de devolución de llamada como argumento. Luego ejecuta esta función de devolución de llamada para cada elemento de la matriz. A diferencia de la map()función, la función forEach no devuelve nada ( undefined). Por ejemplo:
let arr =[1,2,3,4,5];
arr.forEach((element, index, array)=>{
console.log(element *2);if(index ===4){
console.log(array)}// index, and oldArray are provided as 2nd and 3th argument by the callback})
console.log(arr);
Al igual que la mapfunción, la forEachdevolución de llamada proporciona el número de índice de la iteración actual como un segundo argumento. Además, ¿el tercer argumento proporciona la matriz en la que forEachse llamó?
Recorrer elementos usando for..of
El for..ofbucle recorre cada elemento de una matriz (o cualquier otro objeto iterable). Funciona de la siguiente manera:
let arr =[1,2,3,4,5];for(let element of arr){
console.log(element *2);}
En el ejemplo anterior, elementrepresenta un elemento de matriz y arres la matriz que queremos recorrer. Tenga en cuenta que el nombreelement es arbitrario, y podríamos haber elegido cualquier otro nombre como 'el' o algo más declarativo cuando sea aplicable.
No confundas el for..inbucle con el for..ofbucle. for..inrecorrerá todas las propiedades enumerables de la matriz, mientras que el for..ofciclo solo recorrerá los elementos de la matriz. Por ejemplo:
let arr =[1,2,3,4,5];
arr.foo ='foo';for(let element of arr){
console.log(element);}for(let element in arr){
console.log(element);}
forEach
y no solofor
. como se dijo, en C # fue un poco diferente, y eso me confundió :)i < len
yi++
puede hacerlo el motor, en lugar del intérprete.)Respuestas:
TL; DR
for-in
menos que lo use con medidas de seguridad o al menos sepa por qué podría morderlo.Tus mejores apuestas son usualmente
for-of
bucle (solo ES2015 +),Array#forEach
(spec
|MDN
) (o sus parientessome
y demás) (solo ES5 +),for
bucle pasado de moda ,for-in
con salvaguardas.Pero hay mucho más por explorar, sigue leyendo ...
JavaScript tiene una semántica poderosa para recorrer las matrices y los objetos de tipo matriz. He dividido la respuesta en dos partes: opciones para matrices genuinas y opciones para cosas que son simplemente como matrices, como el
arguments
objeto, otros objetos iterables (ES2015 +), colecciones DOM, etc.Notaré rápidamente que puede usar las opciones de ES2015 ahora , incluso en motores ES5, al trasladar ES2015 a ES5. Busque "Transpiling ES2015" / "Transpiling ES6" para más ...
Bien, veamos nuestras opciones:
Para matrices reales
Tiene tres opciones en ECMAScript 5 ("ES5"), la versión más ampliamente admitida en este momento y dos más agregadas en ECMAScript 2015 ("ES2015", "ES6"):
forEach
y relacionados (ES5 +)for
bucle simplefor-in
correctamentefor-of
(usar un iterador implícitamente) (ES2015 +)Detalles:
1. Uso
forEach
y relacionadosEn cualquier entorno vagamente moderno (por lo tanto, no IE8) donde tiene acceso a las
Array
funciones agregadas por ES5 (directamente o usando polyfills), puede usarforEach
(spec
|MDN
):forEach
acepta una función de devolución de llamada y, opcionalmente, un valor para usar comothis
cuando se llama a esa devolución de llamada (no utilizada anteriormente). Se llama a la devolución de llamada para cada entrada en la matriz, en orden, omitiendo las entradas inexistentes en matrices dispersas. Aunque solo utilicé un argumento anterior, la devolución de llamada se llama con tres: el valor de cada entrada, el índice de esa entrada y una referencia a la matriz sobre la que está iterando (en caso de que su función no lo tenga a mano) )A menos que sea compatible con navegadores obsoletos como IE8 (que NetApps muestra con una participación de mercado de poco más del 4% a partir de este escrito en septiembre de 2016), puede usarlo felizmente
forEach
en una página web de uso general sin una cuña. Si necesita admitir navegadores obsoletos, el shimming / polyfillingforEach
se realiza fácilmente (busque "es5 shim" para ver varias opciones).forEach
tiene el beneficio de que no tiene que declarar las variables de indexación y valor en el ámbito que lo contiene, ya que se proporcionan como argumentos para la función de iteración, y se enfocan tan bien en esa iteración.Si le preocupa el costo de tiempo de ejecución de realizar una llamada de función para cada entrada de matriz, no se preocupe; detalles .
Además,
forEach
es la función de "recorrer a través de todos", pero ES5 definió varias otras funciones útiles de "trabajar a través de la matriz y hacer cosas", que incluyen:every
(deja de repetirse la primera vez que vuelve la devolución de llamadafalse
o algo falsey)some
(deja de repetirse la primera vez que vuelve la devolución de llamadatrue
o algo verdadero)filter
(crea una nueva matriz que incluye elementos donde regresa la función de filtrotrue
y omite los que regresafalse
)map
(crea una nueva matriz a partir de los valores devueltos por la devolución de llamada)reduce
(construye un valor llamando repetidamente a la devolución de llamada, pasando valores anteriores; consulte la especificación para obtener detalles; útil para sumar el contenido de una matriz y muchas otras cosas)reduceRight
(comoreduce
, pero funciona en orden descendente en lugar de ascendente)2. Use un
for
bucle simpleA veces las viejas formas son las mejores:
Si la longitud de la matriz no cambiará durante el bucle, y es en el código sensibles al rendimiento (poco probable), una versión ligeramente más complicado agarrar la longitud en la delantera podría ser un pequeño poco más rápido:
Y / o contando hacia atrás:
Pero con los motores JavaScript modernos, es raro que necesites sacar ese último jugo.
En ES2015 y superior, puede hacer que sus variables de índice y valor sean locales en el
for
ciclo:Mostrar fragmento de código
Y cuando haces eso, no solo se recrea
value
sino que tambiénindex
se recrea para cada iteración del bucle, lo que significa que los cierres creados en el cuerpo del bucle mantienen una referencia alindex
(yvalue
) creado para esa iteración específica:Mostrar fragmento de código
Si tuviera cinco divs, obtendría "Índice es: 0" si hizo clic en el primero e "Índice es: 4" si hizo clic en el último. Esto no funciona si lo usa en
var
lugar delet
.3. Usar
for-in
correctamenteObtendrá personas que le dicen que use
for-in
, pero eso nofor-in
es para lo que sirve .for-in
recorre las propiedades enumerables de un objeto , no los índices de una matriz. El pedido no está garantizado , ni siquiera en ES2015 (ES6). ES2015 + define un orden para las propiedades de los objetos (vía[[OwnPropertyKeys]]
,[[Enumerate]]
y las cosas que los usan comoObject.getOwnPropertyKeys
), pero no definió quefor-in
seguiría ese orden; ES2020 lo hizo, sin embargo. (Detalles en esta otra respuesta ).Los únicos casos de uso reales para
for-in
una matriz son:Mirando solo ese primer ejemplo: puede usar
for-in
para visitar esos elementos de matriz dispersos si usa las salvaguardas apropiadas:Tenga en cuenta los tres controles:
Que el objeto tiene su propia propiedad con ese nombre (no uno que herede de su prototipo), y
Que la clave son todos los dígitos decimales (p. Ej., Forma de cadena normal, no notación científica), y
Que el valor de la clave cuando se coacciona a un número es <= 2 ^ 32 - 2 (que es 4,294,967,294). ¿De dónde viene ese número? Es parte de la definición de un índice de matriz en la especificación . Otros números (no enteros, números negativos, números mayores que 2 ^ 32 - 2) no son índices de matriz. La razón por la que es 2 ^ 32 - 2 es que eso hace que el mayor valor del índice sea menor que 2 ^ 32 - 1 , que es el valor máximo que
length
puede tener una matriz . (Por ejemplo, la longitud de una matriz cabe en un entero sin signo de 32 bits). (Apoya a RobG por señalar en un comentario en mi publicación de blog que mi prueba anterior no era del todo correcta).No harías eso en código en línea, por supuesto. Escribirías una función de utilidad. Quizás:
Mostrar fragmento de código
4. Uso
for-of
(use un iterador implícitamente) (ES2015 +)ES2015 agregó iteradores a JavaScript. La forma más fácil de usar iteradores es la nueva
for-of
declaración. Se parece a esto:Debajo de las cubiertas, eso obtiene un iterador del conjunto y lo recorre, obteniendo los valores de él. Esto no tiene el problema que
for-in
tiene usar , porque usa un iterador definido por el objeto (la matriz), y las matrices definen que sus iteradores iteran a través de sus entradas (no sus propiedades). A diferenciafor-in
de ES5, el orden en que se visitan las entradas es el orden numérico de sus índices.5. Use un iterador explícitamente (ES2015 +)
A veces, es posible que desee utilizar un iterador explícitamente . También puedes hacer eso, aunque es mucho más complicado que
for-of
. Se parece a esto:El iterador es un objeto que coincide con la definición de iterador en la especificación. Su
next
método devuelve un nuevo objeto de resultado cada vez que lo llama. El objeto resultante tiene una propiedaddone
que nos dice si está hecho y una propiedadvalue
con el valor para esa iteración. (done
es opcional si lo fuerafalse
,value
es opcional si lo fueraundefined
).El significado de
value
varía según el iterador; Las matrices admiten (al menos) tres funciones que devuelven iteradores:values()
: Este es el que usé arriba. Se devuelve un iterador que cadavalue
es la entrada de la matriz para esa iteración ("a"
,"b"
y"c"
en el ejemplo anterior).keys()
: Devuelve un iterador donde cada unovalue
es la clave para esa iteración (por lo que para nuestroa
anterior, sería"0"
, entonces"1"
, entonces"2"
).entries()
: Devuelve un iterador donde cada unovalue
es una matriz en el formulario[key, value]
para esa iteración.Para objetos tipo matriz
Además de las matrices verdaderas, también hay objetos en forma de matriz que tienen una
length
propiedad y propiedades con nombres numéricos:NodeList
instancias, elarguments
objeto, etc. ¿Cómo recorremos sus contenidos?Use cualquiera de las opciones anteriores para matrices
Al menos algunos, y posiblemente la mayoría o incluso todos, los enfoques de matriz anteriores se aplican con frecuencia igualmente bien a objetos similares a una matriz:
Uso
forEach
y relacionados (ES5 +)Las diversas funciones en
Array.prototype
son "intencionalmente genéricas" y, por lo general, se pueden usar en objetos tipo matriz a través deFunction#call
oFunction#apply
. (Consulte la Advertencia para los objetos proporcionados por el host al final de esta respuesta, pero es un problema poco frecuente).Suponga que desea utilizar
forEach
en unaNode
'schildNodes
propiedad. Harías esto:Si va a hacer eso mucho, es posible que desee obtener una copia de la referencia de función en una variable para su reutilización, por ejemplo:
Usa un
for
bucle simpleObviamente, un
for
bucle simple se aplica a objetos tipo matriz.Usar
for-in
correctamentefor-in
con las mismas garantías que con una matriz, también debería funcionar con objetos similares a una matriz; se puede aplicar la advertencia para los objetos proporcionados por el host en el n. ° 1 anterior.Usar
for-of
(usar un iterador implícitamente) (ES2015 +)for-of
usa el iterador proporcionado por el objeto (si lo hay). Eso incluye objetos proporcionados por el host. Por ejemplo, la especificación paraNodeList
fromquerySelectorAll
se actualizó para admitir la iteración. La especificación para elHTMLCollection
degetElementsByTagName
no era.Use un iterador explícitamente (ES2015 +)
Ver # 4.
Crea una verdadera matriz
Otras veces, es posible que desee convertir un objeto tipo matriz en una matriz verdadera. Hacer eso es sorprendentemente fácil:
Usa el
slice
método de matricesPodemos usar el
slice
método de matrices, que al igual que los otros métodos mencionados anteriormente es "intencionalmente genérico" y, por lo tanto, puede usarse con objetos similares a una matriz, como este:Entonces, por ejemplo, si queremos convertir a
NodeList
en una verdadera matriz, podríamos hacer esto:Vea la Advertencia para los objetos proporcionados por el host a continuación. En particular, tenga en cuenta que esto fallará en IE8 y versiones anteriores, lo que no le permite usar objetos proporcionados por el host de
this
esa manera.Usar sintaxis de propagación (
...
)También es posible usar la sintaxis extendida de ES2015 con motores JavaScript que admiten esta función. Como
for-of
, esto usa el iterador proporcionado por el objeto (ver # 4 en la sección anterior):Entonces, por ejemplo, si queremos convertir una
NodeList
matriz verdadera, con sintaxis extendida esto se vuelve bastante sucinto:Utilizar
Array.from
Array.from
(especificación) | (MDN) (ES2015 +, pero fácilmente rellenado) crea una matriz a partir de un objeto similar a una matriz, opcionalmente pasando primero las entradas a través de una función de mapeo. Entonces:O si desea obtener una matriz de nombres de etiquetas de los elementos con una clase determinada, usaría la función de mapeo:
Advertencia para objetos proporcionados por el host
Si usa
Array.prototype
funciones con objetos de tipo matriz proporcionados por el host (listas DOM y otras cosas proporcionadas por el navegador en lugar del motor de JavaScript), debe asegurarse de realizar pruebas en sus entornos de destino para asegurarse de que el objeto proporcionado por el host se comporta correctamente . La mayoría se comporta correctamente (ahora), pero es importante realizar una prueba. La razón es que la mayoría de losArray.prototype
métodos que es probable que desee utilizar se basan en el objeto proporcionado por el host que da una respuesta honesta a la[[HasProperty]]
operación abstracta . Al escribir estas líneas, los navegadores hacen un muy buen trabajo de esto, pero la especificación 5.1 permitió la posibilidad de que un objeto proporcionado por el host no sea honesto. Está en §8.6.2 , varios párrafos debajo de la gran mesa cerca del comienzo de esa sección), donde dice:(No pude encontrar la verborrea equivalente en la especificación ES2015, pero está obligado a seguir siendo el caso.) Una vez más, a partir de este escrito el host proporcionado por el arreglo de objetos similares en los navegadores modernos [común
NodeList
de los casos, por ejemplo] hacer mango[[HasProperty]]
correctamente, pero es importante hacer la prueba).fuente
.forEach
no se puede romper de manera eficiente. Tienes que lanzar una excepción para realizar el descanso.some
. (Hubiera preferido permitir el descansoforEach
también, pero, um, no me preguntaron. ;-)),
despuésk=0
, no un;
. Recuerde, la programación es muchas cosas, una de las cuales es prestar mucha atención a los detalles ... :-)length
no es un método). :-)Nota : Esta respuesta está irremediablemente desactualizada. Para un enfoque más moderno, mire los métodos disponibles en una matriz . Los métodos de interés pueden ser:
La forma estándar de iterar una matriz en JavaScript es un
for
bucle de vainilla :Sin embargo, tenga en cuenta que este enfoque solo es bueno si tiene una matriz densa y cada índice está ocupado por un elemento. Si la matriz es escasa, entonces puede encontrar problemas de rendimiento con este enfoque, ya que iterará sobre muchos índices que realmente no existen en la matriz. En este caso, un
for .. in
bucle podría ser una mejor idea. Sin embargo , debe usar las salvaguardas apropiadas para garantizar que solo se actúen las propiedades deseadas de la matriz (es decir, los elementos de la matriz), ya que elfor..in
bucle también se enumerará en los navegadores heredados, o si las propiedades adicionales se definen comoenumerable
.En ECMAScript 5 habrá un método forEach en el prototipo de matriz, pero no es compatible con los navegadores heredados. Por lo tanto, para poder usarlo de manera consistente, debe tener un entorno que lo admita (por ejemplo, Node.js para JavaScript del lado del servidor) o usar un "Polyfill". Sin embargo, el Polyfill para esta funcionalidad es trivial y, dado que hace que el código sea más fácil de leer, es un buen polyfill para incluir.
fuente
for(instance in objArray)
no es un uso correcto? me parece más simple, pero escucho que hablas de que no es una forma correcta de uso.var
palabra clave. Si hubiéramos usado un punto y coma, entonceselement
habría sido declarado en el ámbito global (o, más bien, JSHint nos habría gritado antes de que llegara a producción).Si está utilizando la biblioteca jQuery , puede usar jQuery.each :
EDITAR:
Según la pregunta, el usuario desea código en javascript en lugar de jquery, por lo que la edición es
fuente
Bucle hacia atrás
Creo que el reverso de loop merece una mención aquí:
Ventajas:
len
variable temporal ni comparararray.length
en cada iteración, ya que cualquiera de las dos podría ser una optimización por minuto.array[i]
), entonces un bucle hacia adelante omitirá el elemento que se desplazó a la izquierda a la posición i , o volverá a procesar el ítem i . desplazado a la derecha. En un bucle for tradicional, puede actualizar i para señalar el siguiente elemento que necesita procesamiento - 1, pero simplemente invertir la dirección de la iteración suele ser una solución más simple y elegante .forEach()
y para ES6for ... of
.Desventajas
¿Debo usarlo siempre?
Algunos desarrolladores usan el bucle inverso para de forma predeterminada , a menos que haya una buena razón para avanzar.
Aunque las ganancias de rendimiento generalmente son insignificantes, grita:
Sin embargo, en la práctica eso no es en realidad una indicación confiable de intención, ya que es indistinguible de aquellas ocasiones en las que te importa el orden y realmente necesitas hacer un ciclo en reversa. Entonces, de hecho, se necesitaría otra construcción para expresar con precisión la intención de "no me importa", algo que actualmente no está disponible en la mayoría de los idiomas, incluido ECMAScript, pero que podría llamarse, por ejemplo,
forEachUnordered()
,.Si el orden no importa, y la eficiencia es una preocupación (en el bucle más interno de un juego o motor de animación), entonces puede ser aceptable usar el bucle inverso para su patrón de inicio. Solo recuerde que ver un bucle inverso para en el código existente no significa necesariamente que el orden sea irrelevante.
Era mejor usar forEach ()
En general, para el código de nivel superior donde la claridad y la seguridad son mayores preocupaciones, anteriormente recomendé usarlo
Array::forEach
como patrón predeterminado para el bucle (aunque en estos días prefiero usarlofor..of
). Las razones para preferirforEach
sobre un bucle inverso son:for
ywhile
bucles).Luego, cuando vea el bucle inverso para su código, es una pista de que se invierte por una buena razón (tal vez una de las razones descritas anteriormente). Y ver un bucle de avance for tradicional puede indicar que puede tener lugar un cambio.
(Si la discusión sobre la intención no tiene sentido para usted, entonces usted y su código pueden beneficiarse al ver la conferencia de Crockford sobre Estilo de programación y su cerebro ).
Ahora es incluso mejor usarlo para ... ¡de!
Existe un debate sobre si es preferible
for..of
oforEach()
no:Para obtener la máxima compatibilidad con el navegador, se
for..of
requiere un polyfill para los iteradores, lo que hace que su aplicación sea un poco más lenta de ejecutar y un poco más grande de descarga.Por esa razón (y para alentar el uso de
map
yfilter
), ¡ algunas guías de estilo front-end se prohíben porfor..of
completo!Pero las preocupaciones anteriores no son aplicables a las aplicaciones de Node.js, donde
for..of
ahora está bien soportado.Y además
await
no funciona por dentroforEach()
. Usarfor..of
es el patrón más claro en este caso.Personalmente, tiendo a usar lo que parece más fácil de leer, a menos que el rendimiento o la minificación se hayan convertido en una preocupación importante. Así que en estos días yo prefiero usar
for..of
en lugar deforEach()
, pero voy a utilizar siempremap
ofilter
ofind
osome
cuando sea aplicable. (Por el bien de mis colegas, rara vez usoreduce
).¿Como funciona?
Notarás que
i--
es la cláusula central (donde generalmente vemos una comparación) y la última cláusula está vacía (donde generalmente vemosi++
). Eso significa quei--
también se usa como condición para la continuación. Crucialmente, se ejecuta y se verifica antes de cada iteración.¿Cómo puede comenzar
array.length
sin explotar?Debido a que se
i--
ejecuta antes de cada iteración, en la primera iteración realmente tendremos acceso al elemento en elarray.length - 1
que evita cualquier problema conlos elementos fuera de los límites de la matrizundefined
.¿Por qué no deja de iterar antes del índice 0?
El ciclo dejará de iterar cuando la condición se
i--
evalúe como un valor falsey (cuando produce 0).El truco es que
--i
, a diferencia , eli--
operador final disminuyei
pero produce el valor antes de la disminución. Su consola puede demostrar esto:> var i = 5; [i, i--, i];
[5, 5, 4]
Así que en la iteración final, i estaba anteriormente 1 y la
i--
expresión cambia a 0 , pero en realidad el rendimiento de 1 (Truthy), y así la condición pasa. En la siguiente iteracióni--
cambia de i a -1 pero produce 0 (falsey), lo que hace que la ejecución se salga inmediatamente del fondo del bucle.En el tradicional for for loop,
i++
y++i
son intercambiables (como señala Douglas Crockford). Sin embargo, en el reverso del bucle for, dado que nuestro decremento también es nuestra expresión de condición, debemos seguiri--
si queremos procesar el elemento en el índice 0.Trivialidades
A algunas personas les gusta dibujar una pequeña flecha en el
for
bucle inverso y terminar con un guiño:Los créditos van a WYL por mostrarme los beneficios y los horrores del bucle inverso.
fuente
Algunos lenguajes de estilo C se utilizan
foreach
para recorrer las enumeraciones. En JavaScript, esto se hace con lafor..in
estructura de bucle :Hay una trampa.
for..in
recorrerá cada uno de los miembros enumerables del objeto y los miembros de su prototipo. Para evitar leer valores que se heredan a través del prototipo del objeto, simplemente verifique si la propiedad pertenece al objeto:Además, ECMAScript 5 ha agregado un
forEach
métodoArray.prototype
que se puede usar para enumerar sobre una matriz usando un calback (el polyfill está en los documentos, por lo que aún puede usarlo para navegadores más antiguos):Es importante tener en cuenta que
Array.prototype.forEach
no se rompe cuando vuelve la devolución de llamadafalse
. jQuery y Underscore.js proporcionan sus propias variacioneseach
para proporcionar bucles que se pueden cortocircuitar.fuente
each
métodos que permitenreturn false
ser utilizados para salir del ciclo, pero conforEach
esto no es una opción. Se podría usar un indicador externo (es decirif (flag) return;
, pero solo evitaría que el resto del cuerpo de la función se ejecute,forEach
seguiría iterando en toda la colección.Si desea realizar un bucle sobre una matriz, use el
for
bucle estándar de tres partes .Puede obtener algunas optimizaciones de rendimiento al almacenar en caché
myArray.length
o iterar al revés.fuente
length
. ;),
después de una tarea no introduce un nuevo global, por lo que su sugerencia está bien . Estaba confundiendo esto por un problema diferente: usar=
después de una asignación crea un nuevo global.var i, length, arrayItem;
antes del bucle para evitar este malentendido.Sé que esta es una publicación antigua, y ya hay muchas respuestas geniales. Para un poco más de integridad, pensé que lanzaría otro usando AngularJS . Por supuesto, esto solo se aplica si está usando Angular, obviamente, sin embargo, me gustaría ponerlo de todos modos.
angular.forEach
toma 2 argumentos y un tercer argumento opcional. El primer argumento es el objeto (matriz) para iterar, el segundo argumento es la función iteradora, y el tercer argumento opcional es el contexto del objeto (básicamente denominado dentro del bucle como 'esto'.Hay diferentes formas de usar el bucle forEach de angular. El más simple y probablemente el más utilizado es
Otra forma útil para copiar elementos de una matriz a otra es
Sin embargo, no tiene que hacer eso, simplemente puede hacer lo siguiente y es equivalente al ejemplo anterior:
Ahora hay ventajas y desventajas de usar el
angular.forEach
función en lugar delfor
bucle incorporado con sabor a vainilla .Pros
angular.forEach
usará el ES5 para cada bucle. Ahora, llegaré a la eficiencia en la sección contras, ya que los bucles forEach son mucho más lentos que los bucles for. Menciono esto como un profesional porque es bueno ser consistente y estandarizado.Considere los siguientes 2 bucles anidados, que hacen exactamente lo mismo. Digamos que tenemos 2 matrices de objetos y cada objeto contiene una matriz de resultados, cada uno de los cuales tiene una propiedad Value que es una cadena (o lo que sea). Y digamos que necesitamos iterar sobre cada uno de los resultados y si son iguales, entonces realice alguna acción:
De acuerdo, este es un ejemplo hipotético muy simple, pero he escrito triple incrustado para bucles utilizando el segundo enfoque y fue muy difícil de leer y escribir.
Contras
angular.forEach
, y los nativosforEach
, para el caso, son mucho más lentos que elfor
ciclo normal ... aproximadamente un 90% más lento . Por lo tanto, para conjuntos de datos grandes, es mejor atenerse alfor
ciclo nativo .continue
en realidad está respaldado por " accidente ", para continuar en unangular.forEach
simple poner unareturn;
declaración en la función comoangular.forEach(array, function(item) { if (someConditionIsTrue) return; });
que hará que continúe fuera de la función para esa iteración. Esto también se debe al hecho de que el nativoforEach
no admite interrupción o continuación tampoco.Estoy seguro de que también hay otros pros y contras, y siéntase libre de agregar cualquiera que considere conveniente. Creo que, en resumen, si necesita eficiencia, quédese solo con el
for
bucle nativo para sus necesidades de bucle. Pero, si sus conjuntos de datos son más pequeños y se puede renunciar a una cierta eficiencia a cambio de legibilidad y capacidad de escritura, entonces de todos modos arrojeangular.forEach
a ese chico malo.fuente
Si no te importa vaciar la matriz:
x
contendrá el último valor dey
y se eliminará de la matriz. También puede usarshift()
cual le dará y quitará el primer elementoy
.fuente
[1, 2, undefined, 3]
.[1, 2, 0, 3]
o[true, true, false, true]
Una implementación forEach ( ver en jsFiddle ):
fuente
Probablemente el
for(i = 0; i < array.length; i++)
bucle no sea la mejor opción. ¿Por qué? Si tienes esto:El método llamará de
array[0]
aarray[2]
. Primero, esto primero hará referencia a variables que ni siquiera tiene, segundo no tendría las variables en la matriz, y tercero esto hará que el código sea más audaz. Mira aquí, es lo que uso:Y si quieres que sea una función, puedes hacer esto:
Si quieres romper, un poco más de lógica:
Ejemplo:
Vuelve:
fuente
Hay tres implementaciones de
foreach
en jQuery de la siguiente manera.fuente
A partir de ECMAScript 6:
Donde
of
evita las rarezas asociadasin
y hace que funcione como elfor
bucle de cualquier otro lenguaje, y selet
unei
dentro del bucle en lugar de dentro de la función.Las llaves (
{}
) se pueden omitir cuando solo hay un comando (por ejemplo, en el ejemplo anterior).fuente
Una solución fácil ahora sería usar la biblioteca underscore.js . Proporciona muchas herramientas útiles, como
each
y delegará automáticamente el trabajo al nativoforEach
si está disponible.Un ejemplo de CodePen de cómo funciona es:
Ver también
Array.prototype.forEach()
.for each (variable in object)
está en desuso como parte del estándar ECMA-357 ( EAX ).for (variable of object)
como parte de la propuesta de Harmony (ECMAScript 6).fuente
No hay ningún
for each
bucle en JavaScript nativo . Puede usar bibliotecas para obtener esta funcionalidad (recomiendo Underscore.js ), use unfor
bucle simple .Sin embargo, tenga en cuenta que puede haber razones para usar un
for
bucle aún más simple (consulte la pregunta de desbordamiento de pila ¿ Por qué usar "for ... in" con iteración de matriz es una mala idea? )fuente
Este es un iterador para una lista NO dispersa donde el índice comienza en 0, que es el escenario típico cuando se trata de document.getElementsByTagName o document.querySelectorAll)
Ejemplos de uso:
Ejemplo 1
Ejemplo # 2
Cada etiqueta p obtiene
class="blue"
Ejemplo # 3
Cualquier otra etiqueta p obtiene
class="red"
>Ejemplo # 4
Y finalmente las primeras 20 etiquetas p azules se cambian a verde
Precaución al usar una cadena como función: la función se crea fuera de contexto y debe usarse solo cuando esté seguro del alcance variable. De lo contrario, es mejor pasar funciones donde el alcance es más intuitivo.
fuente
Hay algunas formas de recorrer una matriz en JavaScript, como se muestra a continuación:
para - es el más común . Bloque completo de código para bucle
while : bucle mientras se cumple una condición. Parece ser el ciclo más rápido
do / while : también recorre un bloque de código mientras la condición es verdadera, se ejecutará al menos una vez
Bucles funcionales -
forEach
,map
,filter
, tambiénreduce
(que bucle a través de la función, pero se utilizan si hay que hacer algo con su matriz, etc.Para obtener más información y ejemplos sobre programación funcional en matrices, consulte la publicación de blog Programación funcional en JavaScript: mapear, filtrar y reducir .
fuente
forEach
no es un bucle "funcional" ya que no devuelve uno nuevoArray
(en realidad no devuelve nada), solo itera.ECMAScript 5 (la versión en JavaScript) para trabajar con matrices:
forEach : repite cada elemento de la matriz y hace lo que sea necesario con cada elemento.
En el caso, más interesado en la operación en matriz utilizando alguna característica incorporada.
map : crea una nueva matriz con el resultado de la función de devolución de llamada. Este método es bueno para usarse cuando necesita formatear los elementos de su matriz.
reducir : como su nombre lo indica, reduce la matriz a un solo valor llamando a la función dada que pasa en el elemento actual y el resultado de la ejecución anterior.
cada - Devuelve verdadero o falso si todos los elementos de la matriz pasan la prueba en la función de devolución de llamada.
filtro : muy similar a todos excepto que el filtro devuelve una matriz con los elementos que devuelven verdadero a la función dada.
fuente
No hay capacidad incorporada para entrar
forEach
. Para interrumpir la ejecución, use loArray#some
siguiente:Esto funciona porque
some
devuelve verdadero tan pronto como cualquiera de las devoluciones de llamada, ejecutadas en orden de matriz, devuelve verdadero, cortocircuitando la ejecución del resto. Respuesta original ver prototipo de matriz para algunosfuente
También me gustaría agregar esto como una composición de un bucle inverso y una respuesta anterior para alguien a quien también le gustaría esta sintaxis.
Pros:
El beneficio para esto: ya tiene la referencia en el primero, así no será necesario declararla más adelante con otra línea. Es útil al recorrer en bucle la matriz de objetos.
Contras:
Esto se romperá siempre que la referencia sea falsa: falsey (indefinida, etc.). Sin embargo, se puede usar como una ventaja. Sin embargo, sería un poco más difícil de leer. Y también, dependiendo del navegador, puede "no" estar optimizado para funcionar más rápido que el original.
fuente
Forma jQuery usando
$.map
:fuente
[undefined, 2, undefined, 4, undefined, 6, undefined]
.Uso de bucles con la desestructuración de ECMAScript 6 y el operador de propagación
La desestructuración y el uso del operador de propagación han demostrado ser bastante útiles para los recién llegados a ECMAScript 6 por ser más legibles / estéticos, aunque algunos veteranos de JavaScript podrían considerarlo desordenado. Juniors o algunas otras personas pueden encontrarlo útil.
Ejemplo 1:
for...of
bucle normal : no hay trucos aquí.Ejemplo 2: dividir palabras en caracteres
Ejemplo 3: Bucle con una
key
yvalue
Ejemplo 4: obtener las propiedades del objeto en línea
Ejemplo 5: Obtenga propiedades de objetos profundos de lo que necesita
Ejemplo 6: ¿Se usa el ejemplo 3 con
.forEach
Ejemplo 7: ¿Se usa el ejemplo 4 con
.forEach
Ejemplo 8: ¿ Se usa el ejemplo 5 con
.forEach
fuente
Una forma más cercana a su idea sería usar una
Array.forEach()
que acepte una función de cierre que se ejecutará para cada elemento de la matriz.Otra forma viable sería usar el
Array.map()
que funciona de la misma manera, pero también toma todos los valores que devuelve y los devuelve en una nueva matriz (esencialmente asignando cada elemento a uno nuevo), de esta manera:fuente
map
no muta los elementos de la matriz, porque devuelve una nueva matriz, siendo los elementos de esa nueva el resultado de aplicar la función a los elementos de la matriz anterior.Puedes llamar a cada uno de estos:
forEach
iterará sobre la matriz que proporcione y para cada iteración tendráelement
el valor de esa iteración. Si necesita un índice, puede obtener el índice actual pasandoi
el segundo parámetro en la función de devolución de llamada para forEach.Foreach es básicamente una función de orden superior, que toma otra función como parámetro.
Salida:
También puede iterar sobre una matriz como esta:
fuente
Si desea recorrer un conjunto de objetos con la función de flecha:
fuente
La sintaxis lambda no suele funcionar en Internet Explorer 10 o inferior.
Usualmente uso el
Si eres un fanático de jQuery y ya tienes un archivo jQuery en ejecución, debes invertir las posiciones de los parámetros de índice y valor
fuente
Si tiene una matriz masiva que debe usar
iterators
para ganar algo de eficiencia. Los iteradores son una propiedad de ciertas colecciones de JavaScript (comoMap
,Set
,String
,Array
). Incluso,for..of
utilizaiterator
debajo del capó.Los iteradores mejoran la eficiencia al permitirle consumir los elementos en una lista uno a la vez como si fueran una secuencia. Lo que hace que un iterador sea especial es cómo atraviesa una colección. Otros bucles necesitan cargar toda la colección por adelantado para iterar sobre ella, mientras que un iterador solo necesita conocer la posición actual en la colección.
Accede al elemento actual llamando al
next
método del iterador . El siguiente método devolverá elvalue
del elemento actual y unaboolean
para indicar cuándo ha llegado al final de la colección. El siguiente es un ejemplo de creación de un iterador a partir de una matriz.Transforme su matriz regular en iterador usando un
values()
método como este:También puede transformar su matriz regular en iterador usando
Symbol.iterator
así:También puedes transformar tu regular
array
en algoiterator
así:NOTA :
iterable
por defecto. Úselofor..in
en ese caso porque en lugar de valores funciona con claves.Puedes leer más sobre
iteration protocol
aquí .fuente
Si quieres usarlo
forEach()
, se verá así:Si quieres usarlo
for()
, se verá así:fuente
Según la nueva característica actualizada ECMAScript 6 (ES6) y ECMAScript 2015, puede usar las siguientes opciones con bucles:
fuente
Actuación
Hoy (18/12/2019) realizo prueba en mi v10.13.6 macOS (High Sierra), en Chrome v 79.0, v13.0.4 Safari y Firefox v71.0 (64 bits) - Conclusiones sobre la optimización (y micro-optimización de los cuales generalmente no vale la pena introducirlo en el código porque el beneficio es pequeño, pero la complejidad del código crece).
Parece que el tradicional
for i
( Aa ) es una buena opción para escribir código rápido en todos los navegadores.Las otras soluciones, como
for-of
( Ad ), todas en el grupo C. ... suelen ser de 2 a 10 (y más) veces más lentas que Aa , pero para arreglos pequeños está bien usarlo, en aras de aumentar la claridad del código.Los bucles con longitud de matriz en caché
n
( Ab, Bb, Be ) son a veces más rápidos, a veces no. Probablemente los compiladores detectan automáticamente esta situación e introducen el almacenamiento en caché. Las diferencias de velocidad entre las versiones en caché y no en caché ( Aa, Ba, Bd ) son de aproximadamente ~ 1%, por lo que parece que introducirn
es una microoptimización .Las
i--
soluciones similares en las que el bucle comienza desde el último elemento de matriz ( Ac, Bc ) suelen ser ~ 30% más lentas que las soluciones directas; probablemente la razón sea la forma en que funciona la memoria caché de la CPU : la lectura de memoria directa es más óptima para el almacenamiento en caché de la CPU). Se recomienda NO UTILIZAR tales soluciones.Detalles
En las pruebas calculamos la suma de los elementos de la matriz. Realizo una prueba para matrices pequeñas (10 elementos) y matrices grandes (elementos 1M) y las divido en tres grupos:
for
pruebaswhile
pruebasMostrar fragmento de código
Resultados cruzados del navegador
Resultados para todos los navegadores probados
navegadores **
Matriz con 10 elementos.
Resultados para Chrome. Puede realizar la prueba en su máquina aquí .
Matriz con 1,000,000 de elementos
Resultados para Chrome. Puede realizar la prueba en su máquina aquí
fuente
Resumen:
Al iterar sobre una matriz, a menudo queremos lograr uno de los siguientes objetivos:
Queremos iterar sobre la matriz y crear una nueva matriz:
Array.prototype.map
Queremos iterar sobre la matriz y no crear una nueva matriz:
Array.prototype.forEach
for..of
lazoEn JavaScript, hay muchas formas de lograr ambos objetivos. Sin embargo, algunos son más convenientes que otros. A continuación puede encontrar algunos métodos de uso común (la IMO más conveniente) para lograr la iteración de matriz en JavaScript.
Crear nueva matriz:
Map
map()
es una función ubicada en laArray.prototype
que puede transformar cada elemento de una matriz y luego devuelve una nueva matriz.map()
toma como argumento una función de devolución de llamada y funciona de la siguiente manera:La devolución de llamada que hemos pasado
map()
como argumento se ejecuta para cada elemento. Luego se devuelve una matriz que tiene la misma longitud que la matriz original. En este nuevo elemento de matriz se transforma mediante la función de devolución de llamada que se pasa como argumento paramap()
.La diferencia distintiva entre
map
y otro mecanismo de bucle comoforEach
y unfor..of
bucle es quemap
devuelve una nueva matriz y deja intacta la matriz anterior (excepto si la manipula explícitamente con think likesplice
).Además, tenga en cuenta que la
map
devolución de llamada de la función proporciona el número de índice de la iteración actual como un segundo argumento. Además, ¿el tercer argumento proporciona la matriz en la quemap
se llamó? Algunas veces estas propiedades pueden ser muy útiles.Loop usando
forEach
forEach
es una función en laArray.prototype
que se toma una función de devolución de llamada como argumento. Luego ejecuta esta función de devolución de llamada para cada elemento de la matriz. A diferencia de lamap()
función, la función forEach no devuelve nada (undefined
). Por ejemplo:Al igual que la
map
función, laforEach
devolución de llamada proporciona el número de índice de la iteración actual como un segundo argumento. Además, ¿el tercer argumento proporciona la matriz en la queforEach
se llamó?Recorrer elementos usando
for..of
El
for..of
bucle recorre cada elemento de una matriz (o cualquier otro objeto iterable). Funciona de la siguiente manera:En el ejemplo anterior,
element
representa un elemento de matriz yarr
es la matriz que queremos recorrer. Tenga en cuenta que el nombreelement
es arbitrario, y podríamos haber elegido cualquier otro nombre como 'el' o algo más declarativo cuando sea aplicable.No confundas el
for..in
bucle con elfor..of
bucle.for..in
recorrerá todas las propiedades enumerables de la matriz, mientras que elfor..of
ciclo solo recorrerá los elementos de la matriz. Por ejemplo:fuente