Para cada uno sobre una matriz en JavaScript


4684

¿Cómo puedo recorrer todas las entradas de una matriz usando JavaScript?

Pensé que era algo como esto:

forEach(instance in theArray)

¿Dónde theArrayestá mi matriz, pero esto parece ser incorrecto?


16
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.
Slaven Rezic

36
Array.ForEach es aproximadamente un 95% más lento que para () en cada una de las matrices en JavaScript. Vea esta prueba de rendimiento en línea: jsperf.com/fast-array-foreach a través de coderwall.com/p/kvzbpa
molokoloco

77
Para muchas situaciones, un 95% más lento no será significativo blog.niftysnippets.org/2012/02/foreach-and-runtime-cost.html
David Sykes

77
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"):

  1. Uso forEachy relacionados (ES5 +)
  2. Usa un forbucle simple
  3. Usar for-in correctamente
  4. Usar for-of(usar un iterador implícitamente) (ES2015 +)
  5. 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]);
}

Y / o contando hacia atrás:

var index;
var a = ["a", "b", "c"];
for (index = a.length - 1; index >= 0; --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"

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

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-in correctamente

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:

  • Es una matriz escasa con huecos masivos , o
  • 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 array
var 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]);
    }
}

Tenga en cuenta los tres controles:

  1. Que el objeto tiene su propia propiedad con ese nombre (no uno que herede de su prototipo), y

  2. Que la clave son todos los dígitos decimales (p. Ej., Forma de cadena normal, no notación científica), y

  3. 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:

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-ofdeclaración. Se parece a esto:

const a = ["a", "b", "c"];
for (const val of a) {
    console.log(val);
}

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:

  1. 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`
    });
  2. Usa un forbucle simple

    Obviamente, un forbucle simple se aplica a objetos tipo matriz.

  3. Usar for-in correctamente

    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.

  4. 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.

  5. 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:

  1. 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.

  2. 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")];
  3. 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).


44
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.


2
¿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).
PatrikAkerstrand

239

Si está utilizando la biblioteca jQuery , puede usar jQuery.each :

$.each(yourArray, function(index, value) {
  // do your stuff here
});

EDITAR:

Según la pregunta, el usuario desea código en javascript en lugar de jquery, por lo que la edición es

var length = yourArray.length;   
for (var i = 0; i < length; i++) {
  // Do something with yourArray[i].
}

2
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..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 mapy filter), ¡ algunas guías de estilo front-end se prohíben por for..ofcompleto!

  • Pero las preocupaciones anteriores no son aplicables a las aplicaciones de Node.js, donde for..ofahora está bien soportado.

  • Y además await no funciona por dentro forEach(). Usar for..ofes 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..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++) { ... }   // Forwards

for (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 matriz undefined .

  • ¿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.


3
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).
joeytwiddle

84

Algunos lenguajes de estilo C se utilizan foreachpara recorrer las enumeraciones. En JavaScript, esto se hace con la for..inestructura de bucle :

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

arr.forEach(function (val, index, theArray) {
    //do stuff
});

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.


3
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.


66
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:

angular.forEach(temp, function(item) {
    temp2.push(item);
});

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 loop
for (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.


34

Si no te importa vaciar la matriz:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

xcontendrá el último valor de yy se eliminará de la matriz. También puede usar shift()cual le dará y quitará el primer elemento y.


44
No funciona si tienes una matriz dispersa como [1, 2, undefined, 3].
M. Grzywaczewski

2
... o cualquier cosa falsey: [1, 2, 0, 3]o[true, true, false, true]
joeytwiddle

31

Una implementación forEach ( ver en jsFiddle ):

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

2
iterador en esto, está haciendo un cálculo de longitud innecesario. En un caso ideal, la longitud de la lista debe calcularse solo una vez.
Middun Krishna

2
@MIdhunKrishna Actualicé mi respuesta y el jsFiddle, pero ten en cuenta que no es tan simple como crees. Compruebe esta pregunta
nmoliveira

2
La implementación completa y correcta se puede encontrar aquí: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
marciowb

29

Probablemente el for(i = 0; i < array.length; i++)bucle no sea la mejor opción. ¿Por qué? Si tienes esto:

var array = new Array();
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;
        }
    }
}

Ejemplo:

foreach(array, function(el){
    if(el != "!"){
        console.log(el);
    } else {
        console.log(el+"!!");
    }
});

Vuelve:

//Hello
//World
//!!!

29

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

2
El registro de la consola es solo para la demostración. Eso es para que sea un ejemplo completo de ejecución.
Rajesh Paul

29

A partir de ECMAScript 6:

list = [0, 1, 2, 3]
for (let obj of list) {
    console.log(obj)
}

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


28

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.

Un ejemplo de CodePen de cómo funciona es:

var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});

Ver también


23

No hay ningún for eachbucle en JavaScript nativo . Puede usar bibliotecas para obtener esta funcionalidad (recomiendo Underscore.js ), use un forbucle simple .

for (var instance in objects) {
   ...
}

Sin embargo, tenga en cuenta que puede haber razones para usar un forbucle 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? )

var instance;
for (var i=0; i < objects.length; i++) {
    var instance = objects[i];
    ...
}

22

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

    return this;
}

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]

Ejemplo # 2

each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');

Cada etiqueta p obtiene class="blue"

Ejemplo # 3

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.


21

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;
<p id="example"></p>

while : bucle mientras se cumple una condición. Parece ser el ciclo más rápido

var text = "";
var i = 0;
while (i < 10) {
    text +=  i + ") something<br>";
    i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

do / while : también recorre un bloque de código mientras la condición es verdadera, se ejecutará al menos una vez

var text = ""
var i = 0;

do {
    text += i + ") something <br>";
    i++;
}
while (i < 10);

document.getElementById("example").innerHTML = text;
<p id="example"></p>

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 function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>

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 .


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.

[1,2,3,4].reduce(function(previous, current) {
  return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10

cada - Devuelve verdadero o falso si todos los elementos de la matriz pasan la prueba en la función de devolución de llamada.

// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];
ages.every(function(elem) {
  return elem >= 18;
});

// Output: false

filtro : muy similar a todos excepto que el filtro devuelve una matriz con los elementos que devuelven verdadero a la función dada.

// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
  return (elem % 2 == 0)
});

// Output: [2,4,6]

16

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


13

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.


12

Forma jQuery usando $.map:

var data = [1, 2, 3, 4, 5, 6, 7];

var newData = $.map(data, function(element) {
    if (element % 2 == 0) {
        return element;
    }
});

// newData = [2, 4, 6];

1
Creo que la salida es más probable [undefined, 2, undefined, 4, undefined, 6, undefined].

10

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.

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

Ejemplo 2: dividir palabras en caracteres

let arrFruits = ['apple', 'orange', 'banana'];

for (let [firstLetter, ...restOfTheWord] of arrFruits) {
  // Create a shallow copy using the spread operator
  let [lastLetter] = [...restOfTheWord].reverse();
  console.log(firstLetter, lastLetter, restOfTheWord);
}

Ejemplo 3: Bucle con una keyyvalue

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

Ejemplo 4: obtener las propiedades del objeto en línea

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];

for (let { name, age: aliasForAge } of arrWithObjects) {
  console.log(name, aliasForAge);
}

Ejemplo 5: Obtenga propiedades de objetos profundos de lo que necesita

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
  console.log(name, firstItemFromTags, restOfTags);
}

Ejemplo 6: ¿Se usa el ejemplo 3 con.forEach

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

Ejemplo 7: ¿Se usa el ejemplo 4 con.forEach

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

Ejemplo 8: ¿ Se usa el ejemplo 5 con.forEach

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

arrWithObjectsWithArr.forEach(({
  name,
  tags: [firstItemFromTags, ...restOfTags]
}) => {
  console.log(name, firstItemFromTags, restOfTags);
});


7

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:

var myArray = [1, 2, 3];
myArray = myArray.map(
  (item) => {
    return item + 1;
  }
);

console.log(myArray); // [2, 3, 4]

1
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:

1
3
2

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
}

6

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


6

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

5

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

También puede transformar su matriz regular en iterador usando Symbol.iteratorasí:

const myArr = [2,3,4]

let it = myArr[Symbol.iterator]();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

También puedes transformar tu regular arrayen algo iteratorasí:

let myArr = [8, 10, 12];

function makeIterator(array) {
    var nextIndex = 0;
    
    return {
       next: function() {
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    };
};

var it = makeIterator(myArr);

console.log(it.next().value);   // {value: 8, done: false}
console.log(it.next().value);   // {value: 10, done: false}
console.log(it.next().value);   // {value: 12, done: false}
console.log(it.next().value);   // {value: undefined, done: true}

NOTA :

  • Los iteradores son de naturaleza agotable.
  • Los objetos no son iterablepor defecto. Úselo for..inen ese caso porque en lugar de valores funciona con claves.

Puedes leer más sobre iteration protocol aquí .


5

Si quieres usarlo forEach(), se verá así:

theArray.forEach ( element => {
    console.log(element);
});

Si quieres usarlo for(), se verá así:

for(let idx = 0; idx < theArray.length; idx++){
    let element = theArray[idx];
    console.log(element);
}

4

Según la nueva característica actualizada ECMAScript 6 (ES6) y ECMAScript 2015, puede usar las siguientes opciones con bucles:

para bucles

for(var i = 0; i < 5; i++){
  console.log(i);
}

// Output: 0,1,2,3,4

para ... en bucles

let obj = {"a":1, "b":2}

for(let k in obj){
  console.log(k)
}

// Output: a,b

Array.forEach ()

let array = [1,2,3,4]

array.forEach((x) => {
  console.log(x);
})

// Output: 1,2,3,4

para ... de bucles

let array = [1,2,3,4]

for(let x of array){
  console.log(x);
}

// Output: 1,2,3,4

mientras bucles

let x = 0

while(x < 5){
  console.log(x)
  x++
}

// Output: 1,2,3,4

hacer ... mientras bucles

let x = 0

do{
  console.log(x)
  x++
}while(x < 5)

// Output: 1,2,3,4

4

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 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:

  • A - forpruebas
  • B - whilepruebas
  • C - otros / métodos alternativos

Resultados cruzados del navegador

Resultados para todos los navegadores probados

Ingrese la descripción de la imagen aquínavegadores **

Matriz con 10 elementos.

Resultados para Chrome. Puede realizar la prueba en su máquina aquí .

Ingrese la descripción de la imagen aquí

Matriz con 1,000,000 de elementos

Resultados para Chrome. Puede realizar la prueba en su máquina aquí

Ingrese la descripción de la imagen aquí


4

Resumen:

Al iterar sobre una matriz, a menudo queremos lograr uno de los siguientes objetivos:

  1. Queremos iterar sobre la matriz y crear una nueva matriz:

    Array.prototype.map

  2. Queremos iterar sobre la matriz y no crear una nueva matriz:

    Array.prototype.forEach

    for..of lazo

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.