Pregunta Para-cada uno sobre una matriz en JavaScript?


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

Pensé que era algo como esto:

forEach(instance in theArray)

Dónde theArray es mi matriz, pero esto parece ser incorrecto.


3782
2018-02-17 13:51


origen


Respuestas:


TL; DR

  • No usar for-in a menos que lo use con protecciones o al menos tenga en cuenta por qué podría morderlo.
  • Tus mejores apuestas son usualmente

    • un for-of loop (ES2015 + solamente),
    • Array#forEach (spec | MDN) (o sus parientes) some y tal) (ES5 + solo),
    • un simple pasado de moda for lazo,
    • o for-in con protecciones

Pero hay un montón más para explorar, seguir leyendo ...


JavaScript tiene una poderosa semántica para el bucle a través de matrices y objetos tipo array. He dividido la respuesta en dos partes: opciones para arreglos genuinos y opciones para cosas que son solo arreglosme gusta, tales 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, por transpiling ES2015 a ES5. Buscar "ES2015 transpiling" / "ES6 transpiling" para más ...

Bien, veamos nuestras opciones:

Para Matrices Reales

Tienes tres opciones en ECMAScript 5 ("ES5"), la versión más ampliamente compatible en este momento, y dos más agregados en ECMAScript 2015 ("ES2015", "ES6"):

  1. Utilizar forEach y relacionado (ES5 +)
  2. Use un simple for lazo
  3. Utilizar for-in  correctamente
  4. Utilizar for-of (utilice un iterador implícitamente) (ES2015 +)
  5. Use un iterador explícitamente (ES2015 +)

Detalles:

1. Uso forEach y relacionado

En cualquier entorno vagamente moderno (por lo tanto, no IE8) donde tiene acceso a la Array características agregadas por ES5 (directamente o usando polyfills), puede usar forEach (spec | MDN)

var a = ["a", "b", "c"];
a.forEach(function(entry) {
    console.log(entry);
});

forEach acepta una función de devolución de llamada y, opcionalmente, un valor para usar como this al llamar a esa devolución de llamada (no se usa arriba). Se llama a la devolución de llamada para cada entrada en la matriz, en orden, omitiendo las entradas no existentes en las matrices dispersas. Aunque solo utilicé un argumento anterior, se llama a la devolución de llamada con tres: el valor de cada entrada, el índice de esa entrada y una referencia a la matriz sobre la que se está iterando (en caso de que su función no la tenga ya a mano) )

A menos que esté respaldando navegadores obsoletos como IE8 (que NetApps muestra en un poco más del 4% del mercado al momento de escribir estas líneas en septiembre de 2016), puede usarlo con gusto forEach en una página web de propósito general sin una cuña. Si necesita admitir navegadores obsoletos, shimming / polyfilling forEach se realiza fácilmente (busque "es5 shim" para obtener varias opciones).

forEach tiene la ventaja de que no tiene que declarar las variables de indexación y valor en el ámbito que lo contiene, ya que se suministran como argumentos a la función de iteración, y tan bien enfocado a esa iteración.

Si le preocupa el costo del tiempo de ejecución de realizar una llamada de función para cada entrada de matriz, no lo haga; detalles.

Adicionalmente, forEach es la función "bucle a través de todos", pero ES5 definió varias otras funciones útiles "avance a través de la matriz y haga cosas", que incluyen:

  • every (deja de repetirse la primera vez que regresa la devolución de llamada false o algo falsey)
  • some (deja de repetirse la primera vez que regresa la devolución de llamada true o algo sincero)
  • filter (crea una nueva matriz que incluye elementos donde regresa la función de filtro true y omitiendo aquellos en los que regresa false)
  • map (crea una nueva matriz a partir de los valores devueltos por la devolución de llamada)
  • reduce (crea un valor llamando repetidamente a la devolución de llamada, pasando los valores anteriores, ver la especificación de los detalles, útil para sumar el contenido de una matriz y muchas otras cosas)
  • reduceRight (me gusta reduce, pero funciona en orden descendente en vez de ascendente)

2. Usa un simple for lazo

Algunas 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 cambia durante el ciclo, y está en el código sensible al rendimiento (poco probable), una versión un poco más complicada que tome la longitud inicial podría ser una minúsculo un 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 modernos de JavaScript, es raro que necesite extraer ese último zumo.

En ES2015 y superior, puede hacer que sus variables de índice y valor sean locales para el for lazo:

let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
    let value = a[index];
}
//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 value pero también index se recrea para cada iteración de bucle, lo que significa que los cierres creados en el cuerpo del bucle guardan 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 => {
        alert("Index is: " + index);
    });
}

Si tuviera cinco divs, obtendría "Index is: 0" si hizo clic en el primero y "Index is: 4" si hizo clic en el último. Esto hace no funciona si usas var en lugar de let.

3. Uso for-in  correctamente

Conseguirás que la gente te diga que uses for-in, pero eso no es lo que for-in es para. for-in pasa por el propiedades enumerables de un objeto, no los índices de una matriz. La orden no está garantizada, ni siquiera en ES2015 (ES6). ES2015 define un orden para las propiedades del objeto (a través de [[OwnPropertyKeys]], [[Enumerate]]y cosas que los usan como Object.getOwnPropertyKeys), pero no definir eso for-in seguirá ese orden (Detalles en esta otra respuesta.)

Aún así, poder ser útil, particularmente para escaso matrices, si usa las protecciones adecuadas:

// `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 are explained
        /^0$|^[1-9]\d*$/.test(key) &&    // and then hidden
        key <= 4294967294                // away below
        ) {
        console.log(a[key]);
    }
}

Tenga en cuenta los dos controles:

  1. Que el objeto tiene su propio propiedad con ese nombre (no uno hereda de su prototipo), y

  2. Que la clave es una cadena numérica de base 10 en su forma de cadena normal y su valor 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 es 2 ^ 32 - 2 es que eso hace que el mayor valor del índice sea uno inferior a 2 ^ 32 - 1, que es el valor máximo de una matriz length puede tener. (Por ejemplo, la longitud de una matriz cabe en un entero sin signo de 32 bits). (Apoyos para RobG para señalar en un comentario en mi publicación de blog que mi prueba anterior no fue del todo correcta.)

Eso es un poco de sobrecarga añadida por iteración de bucle en la mayoría de las matrices, pero si tiene una escaso array, puede ser una forma más eficiente de bucle porque solo realiza un bucle para las entradas que realmente existen. Por ejemplo, para la matriz anterior, hacemos un ciclo de un total de tres veces (para las claves "0", "10"y "10000"- recuerda, son cuerdas), no 10,001 veces.

Ahora, no querrá escribir eso cada vez, así que puede poner esto en su kit de herramientas:

function arrayHasOwnIndex(array, prop) {
    return array.hasOwnProperty(prop) && /^0$|^[1-9]\d*$/.test(prop) && prop <= 4294967294; // 2^32 - 2
}

Y luego lo usaríamos así:

for (key in a) {
    if (arrayHasOwnIndex(a, key)) {
        console.log(a[key]);
    }
}

O si está interesado solo en una prueba "lo suficientemente buena para la mayoría de los casos", puede usar esto, pero mientras está cerca, no es del todo correcto:

for (key in a) {
    // "Good enough" for most cases
    if (String(parseInt(key, 10)) === key && a.hasOwnProperty(key)) {
        console.log(a[key]);
    }
}

4. Uso for-of (utilice un iterador implícitamente) (ES2015 +)

ES2015 agrega iteradores a JavaScript La forma más fácil de usar iteradores es la nueva for-of declaración. Se parece a esto:

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

Salida:

un
segundo
do

Bajo las sábanas, eso se convierte en iterador de la matriz y pasa a través de ella, obteniendo los valores de ella. Esto no tiene el problema de que usar for-in tiene, porque utiliza un iterador definido por el objeto (la matriz), y las matrices definen que sus iteradores iteran a través de su entradas (no sus propiedades). diferente a for-in en 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. Puedes hacer eso también, aunque es mucho más ruidoso que for-of. Se parece a esto:

var a = ["a", "b", "c"];
var it = a.values();
var entry;
while (!(entry = it.next()).done) {
    console.log(entry.value);
}

El iterador es un objeto que coincide con la definición de Iterator en la especificación. Sus next método devuelve un nuevo objeto resultante cada vez que lo llamas. El objeto resultante tiene una propiedad, done, diciéndonos si ya está hecho, y una propiedad value con el valor de esa iteración. (done es opcional si fuera false, value es opcional si fuera undefined.)

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 utilicé arriba. Devuelve un iterador donde cada value es la entrada de la matriz para esa iteración ("a", "b"y "c" en el ejemplo anterior).
  • keys(): Devuelve un iterador donde cada value es la clave para esa iteración (entonces para nuestra a arriba, eso sería "0", entonces "1", entonces "2")
  • entries(): Devuelve un iterador donde cada value es una matriz en forma [key, value] para esa iteración.

Para objetos tipo Array

Además de las matrices reales, también hay tipo array objetos que tienen una length propiedad y propiedades con nombres numéricos: NodeList instancias, el arguments objeto, etc. ¿Cómo recorremos sus contenidos?

Use cualquiera de las opciones anteriores para arreglos

Al menos algunos, y posiblemente la mayoría o incluso todos, de los enfoques de matriz anteriores se aplican con frecuencia igualmente bien a los objetos tipo array:

  1. Utilizar forEach y relacionado (ES5 +)

    Las diversas funciones en Array.prototype son "intencionalmente genéricas" y, por lo general, se pueden usar en objetos similares a una matriz a través de Function#call o Function#apply. (Ver el Advertencia para objetos proporcionados por el host al final de esta respuesta, pero es un problema raro).

    Supongamos que quiere usar forEach en un Nodees childNodes propiedad. Tú harías esto:

    Array.prototype.forEach.call(node.childNodes, function(child) {
        // Do something with `child`
    });
    

    Si vas a hacer eso mucho, es posible que desees 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. Use un simple for lazo

    Obviamente, un simple for loop se aplica a los objetos tipo array.

  3. Utilizar for-in  correctamente

    for-in con las mismas protecciones que con una matriz, debería funcionar también con objetos tipo array; la advertencia para objetos proporcionados por el host en el n. ° 1 anterior puede ser aplicable.

  4. Utilizar for-of (utilice un iterador implícitamente) (ES2015 +)

    for-of usará el iterador proporcionado por el objeto (si lo hay); tendremos que ver cómo funciona esto con los diversos objetos parecidos a los arreglos, especialmente los proporcionados por el anfitrión. Por ejemplo, la especificación para el NodeList de querySelectorAll fue actualizado para apoyar la iteración. La especificación para el HTMLCollection de getElementsByTagName no estaba.

  5. Use un iterador explícitamente (ES2015 +)

    Ver # 4, tendremos que ver cómo funcionan los iteradores.

Crear una verdadera matriz

Otras veces, es posible que desee convertir un objeto similar a una matriz en una verdadera matriz. Hacer eso es sorprendentemente fácil:

  1. Utilizar el slice método de matrices

    Podemos 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, se puede utilizar con objetos tipo array, como este:

    var trueArray = Array.prototype.slice.call(arrayLikeObject);
    

    Entonces, por ejemplo, si queremos convertir un NodeList en una verdadera matriz, podríamos hacer esto:

    var divs = Array.prototype.slice.call(document.querySelectorAll("div"));
    

    Ver el Advertencia para objetos proporcionados por el host abajo. En particular, tenga en cuenta que esto fallará en IE8 y anteriores, que no le permiten usar objetos proporcionados por el host como this como eso.

  2. Utilizar sintaxis de propagación (...)

    También es posible usar ES2015 sintaxis extendida con motores de JavaScript que admiten esta característica:

    var trueArray = [...iterableObject];
    

    Entonces, por ejemplo, si queremos convertir un NodeList en una matriz verdadera, con sintaxis expandida esto se vuelve bastante breve:

    var divs = [...document.querySelectorAll("div")];
    
  3. Utilizar Array.from  (especulación) | (MDN)

    Array.from (ES2015 +, pero se puede rellenar fácilmente) crea una matriz a partir de un objeto similar a una matriz, opcionalmente pasando las entradas a través de una función de mapeo primero. Asi que:

    var divs = Array.from(document.querySelectorAll("div"));
    

    O si quisiera 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 utiliza Array.prototype funciones con proporcionado por el anfitrión objetos similares a una matriz (listas DOM y otras cosas proporcionadas por el navegador en lugar de por el motor JavaScript), debe asegurarse de probar en sus entornos objetivo para asegurarse de que el objeto proporcionado por el host se comporta correctamente. La mayoría se comporta correctamente (ahora), pero es importante probarlo. La razón es que la mayoría de Array.prototype los métodos que probablemente quiera utilizar dependen del objeto proporcionado por el host que da una respuesta honesta al resumen [[HasProperty]] operación. Al escribir estas líneas, los navegadores hacen un muy buen trabajo al respecto, pero la especificación 5.1 sí permitió la posibilidad de que un objeto proporcionado por el host no fuera honesto. Está dentro §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 en particular, de hecho, recuperar y almacenar los valores de propiedad, pero [[HasProperty]] siempre genera falso.

(No pude encontrar la verborrea equivalente en la especificación ES2015, pero aún debe ser el caso). Una vez más, a partir de esta redacción, los objetos tipo array parecidos a host comunes en los navegadores modernos [NodeList instancias, por ejemplo] hacer encargarse de [[HasProperty]] correctamente, pero es importante probar).


5976
2018-02-17 13:53



Editar: Esta respuesta está irremediablemente desactualizada. Para un enfoque más moderno, mira los métodos disponibles en una matriz. Los métodos de interés podrían ser:

  • para cada
  • mapa
  • filtrar
  • cremallera
  • reducir
  • cada
  • algunos

La forma estándar de iterar una matriz en JavaScript es un vainilla for-lazo:

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

Tenga en cuenta, sin embargo, 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 encontrarse con problemas de rendimiento con este enfoque, ya que iterará sobre una gran cantidad de índices que no lo hacen. De Verdad existir en la matriz. En este caso, un for .. in-loop podría ser una mejor idea. sin embargo, debe usar las medidas de seguridad adecuadas para garantizar que solo se actúe sobre las propiedades deseadas de la matriz (es decir, los elementos de la matriz), ya que la for..in-loop también se enumerará en los navegadores heredados, o si las propiedades adicionales se definen como enumerable.

En ECMAScript 5 Habrá un método para cada método en el prototipo de matriz, pero no es compatible con los navegadores heredados. Entonces, para poder usarlo consistentemente, debe tener un entorno que lo soporte (por ejemplo, Node.js para el lado del servidor JavaScript), o use un "Polyfill". El Polyfill para esta funcionalidad es, sin embargo, trivial y dado que hace que el código sea más fácil de leer, es un buen polyfill para incluir.


451
2018-02-17 13:55



Si estás usando el jQuery biblioteca, puedes usar jQuery.each:

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

EDITAR: 

Según la pregunta, el usuario quiere código en javascript en lugar de jquery para que la edición sea

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

205
2018-02-17 14:01



Loop hacia atrás

Pienso que el marcha atrás para loop merece una mención aquí:

for (var i = array.length; i--; ) {
     // process array[i]
}

Ventajas:

  • No necesita declarar un temporal len variable, o comparar contra array.length en cada iteración, cualquiera de las cuales podría ser una optimización de minutos.
  • Eliminando hermanos desde el DOM en orden inverso es generalmente más eficiente. (El navegador necesita hacer menos cambios de elementos en sus matrices internas).
  • Si tu modificar la matriz mientras buclea, en o después del índice yo (por ejemplo, eliminar o insertar un elemento en array[i]), luego un bucle hacia adelante omitiría el elemento que se desplazó a la izquierda en posición yo, o reprocesar el yoel elemento que se desplazó a la derecha. En un ciclo for tradicional, podría actualizar yo para apuntar al siguiente elemento que necesita procesamiento - 1, pero simplemente invertir la dirección de la iteración suele ser un más simple y una solución más elegante.
  • Del mismo modo, al modificar o eliminar anidado Elementos DOM, procesamiento en reversa puede evitar errores. Por ejemplo, considere modificar el innerHTML de un nodo primario antes de manejar sus hijos. Para cuando se llegue al nodo secundario, se separará del DOM, habiendo sido reemplazado por un elemento secundario creado cuando se escribió elHTML interno de los padres.
  • Es corta escribir, y leer, que algunas de las otras opciones disponibles. Aunque pierde a forEach() y a ES6 for ... of.

Desventajas:

  • Procesa los elementos en orden inverso. Si estaba construyendo una nueva matriz a partir de los resultados, o imprimiendo cosas en la pantalla, naturalmente la salida se invertirá con respecto a la orden original.
  • Insertar repetidamente hermanos en el DOM como primer hijo para retener su orden es menos eficiente. (El navegador tendría que seguir cambiando las cosas a la derecha.) Para crear nodos DOM de manera eficiente y en orden, simplemente realice un bucle hacia delante y anexe de forma normal (y también use un "fragmento de documento").
  • El ciclo inverso es confuso a los desarrolladores junior. (Puede considerar que es una ventaja, dependiendo de su punto de vista).

¿Debería usarlo siempre?

Algunos desarrolladores usan el reverso para el bucle por defecto, a menos que haya una buena razón para seguir adelante.

Aunque las ganancias de rendimiento son usualmente insignificantes, de alguna manera grita:

"Simplemente haz esto con cada elemento de la lista, ¡no me importa el orden!"

Sin embargo, en la práctica eso es no en realidad una indicación confiable de intención, ya que es indistinguible de aquellas ocasiones en que hacer se preocupan por el orden, y realmente lo hacen necesitar para repetir en reversa De hecho, se necesitaría otro constructo para expresar con precisión el intento 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 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 ciclo inverso para bucle como su patrón de acceso. Solo recuerda que viendo un revés para el bucle en el código existente no necesariamente significa ¡que la orden es irrelevante!

Es mejor usar forEach ()

En general, para el código de nivel superior donde claridad y seguridad son preocupaciones mayores, recomendaría usar Array::forEach como su patrón predeterminado:

  • Está claro para leer.
  • Indica que yo no se va a desplazar dentro del bloque (que siempre es una posible sorpresa escondida en el largo for y while bucles.)
  • Le da un alcance libre para cierres.
  • Reduce la fuga de variables locales y la colisión accidental con (y la mutación) de las variables externas.

Luego, cuando veas el reverso de un bucle en tu código, esa es una pista de que se revierte por una buena razón (quizás una de las razones descritas anteriormente). Y ver un ciclo forward for tradicional puede indicar que se puede producir un cambio.

(Si la discusión de intenciones no tiene sentido para usted, entonces usted y su código pueden beneficiarse viendo la conferencia de Crockford sobre Programación de estilo y su cerebro.)


¿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 media (donde solemos ver una comparación) y la última cláusula está vacía (donde solemos ver i++) Eso significa que i-- también se usa como el condición para la continuación. Fundamentalmente, se ejecuta y verifica antes de cada iteración.

  • ¿Cómo puede comenzar en array.length sin explotar?

    Porque i-- carreras antes de cada iteración, en la primera iteración accederemos al ítem en array.length - 1 que evita cualquier problema con Array-out-of-bounds  undefined artículos.

  • ¿Por qué no deja de iterar antes del índice 0?

    El ciclo dejará de iterar cuando la condición i-- evalúa a un valor de falsey (cuando rinde 0).

    El truco es que a diferencia --i, el final i-- decrementos de operador i pero rinde el valor antes de la disminución Tu consola puede demostrar esto:

    > var i = 5; [i, i--, i];

    [5, 5, 4]

    Entonces en la iteración final, yo fue previamente 1 y el i-- expresión lo cambia a 0 pero en realidad rinde 1 (Verdad), y entonces la condición pasa. En la próxima iteración i-- cambios yo a -1 pero rinde 0 (falsey), lo que hace que la ejecución caiga inmediatamente fuera del ciclo.

    En los forwards tradicionales para loop, i++ y ++i son intercambiables (como señala Douglas Crockford). Sin embargo, en el reverso de loop, porque nuestra disminución también es nuestra expresión de condición, debemos seguir con i-- si queremos procesar el artículo en el índice 0.


Trivialidades

A algunas personas les gusta dibujar una pequeña flecha en el reverso for loop, y termina 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 reverso para el ciclo.


88
2018-05-02 14:21



Algunos doestilo de estilo de uso foreach para recorrer las enumeraciones. En JavaScript, esto se hace con el for..in estructura de bucle:

var index,
    value;
for (index in obj) {
    value = obj[index];
}

Hay una trampa. for..in recorrerá cada uno de los miembros enumerables del objeto y los miembros en 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
    }
}

Adicionalmente, ECMAScript 5 ha agregado un forEach método para Array.prototypeque se puede usar para enumerar a través de una matriz mediante un cálculo de retorno (el relleno policrible se encuentra en los documentos, por lo que aún puede usarlo para navegadores antiguos):

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

Es importante tener en cuenta que Array.prototype.forEach no se rompe cuando regresa la devolución de llamada false. jQuery y Underscore.js proporcionar sus propias variaciones en each para proporcionar bucles que pueden estar en cortocircuito.


71
2018-02-17 14:00



Si desea recorrer una matriz, utilice el estándar de tres partes for lazo.

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

Puede obtener algunas optimizaciones de rendimiento almacenando en caché myArray.length o iterando sobre ella hacia atrás.


30
2018-02-17 13:55



UN para cada implementación (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
  }
);

25
2018-04-10 00:26



Si no te importa vaciar la matriz:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

x contendrá el último valor de y y se eliminará de la matriz. También puedes usar shift() que dará y eliminará el primer elemento de y.


25
2018-03-10 02:37



Sé que esta es una publicación anterior, y ya hay muchas respuestas excelentes. Por un poco más completo, pensé que lanzaría otro utilizando AngularJS. Por supuesto, esto solo se aplica si estás 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 del iterador, y el tercer argumento opcional es el contexto del objeto (referido básicamente dentro del bucle como 'esto'.

Hay diferentes maneras de usar el bucle forEach de angular. El más simple y probablemente el más usado es

var temp = [1, 2, 3];
angular.forEach(temp, function(item) {
    //item will be each element in the array
    //do something
});

Otra forma que es ú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 tienes que hacer eso, simplemente puedes 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 comparación con el construido en sabor a vainilla for lazo.

Pros

  • Facilidad de lectura
  • Escritabilidad fácil
  • Si está disponible, angular.forEach usará el ES5 para cada ciclo. Ahora, llegaré a la eficiencia en la sección de contras, ya que los ciclos forEach son mucho más lento 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 para ese asunto.

Contras

  • Eficiencia. angular.forEachy el nativo forEach, para el caso, son ambos tanto más lento de lo normal for loop .... sobre 90% más lento. Entonces, para grandes conjuntos de datos, lo mejor es apegarse a los nativos for lazo.
  • Sin interrupción, continuación o devolución de soporte. continue en realidad es compatible con "accidente", para continuar en una angular.forEach simplemente pon un return; declaración en la función como angular.forEach(array, function(item) { if (someConditionIsTrue) return; }); lo que hará que continúe fuera de la función para esa iteración. Esto también se debe al hecho de que el nativo forEach no admite interrupción o continúa tampoco.

Estoy seguro de que también hay otros pros y contras, y no dude en añadir los que considere oportunos. Siento que, en definitiva, si necesita eficiencia, quédese solo con el nativo for bucle para sus necesidades de bucle. Pero, si sus conjuntos de datos son más pequeños y se puede renunciar a cierta eficiencia a cambio de legibilidad y capacidad de escritura, entonces, por supuesto, lanzar un angular.forEach en ese chico malo


25
2018-06-20 22:56



Una solución fácil ahora sería usar el biblioteca underscore.js. Proporciona muchas herramientas útiles, como each y automáticamente delegará el trabajo al nativo forEach si 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


24
2017-07-17 09:07



Probablemente el for(i = 0; i < array.length; i++) el bucle no es 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á desde array[0] a array[2]. Primero, esto primero hará referencia a las variables que ni siquiera tiene, en segundo lugar, no tendría las variables en el conjunto, 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
//!!!

21
2017-11-02 02:23