objetos - for array javascript




¿Para cada uno sobre una matriz en JavaScript? (19)

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

Pensé que era algo como esto:

forEach(instance in theArray)

Donde theArray es mi matriz, pero esto parece ser incorrecto.


Bucle hacia atrás

Creo que lo contrario para el bucle merece una mención aquí:

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

Ventajas:

  • No es necesario declarar una variable len temporal ni comparar con array.length en cada iteración, ya que cualquiera de ellas puede ser una optimización de un minuto.
  • Eliminar a los hermanos del DOM en orden inverso suele ser más eficiente . (El navegador debe hacer menos cambios de elementos en sus matrices internas).
  • Si modifica la matriz mientras realiza un bucle, en o después del índice i (por ejemplo, si quita o inserta un elemento en la array[i] ), un bucle hacia adelante omitirá el elemento que se desplazó a la izquierda hasta la posición i , o re-procesa la i. El artículo que fue cambiado a la derecha. En un bucle for tradicional, podría actualizar i para que apunte al 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 .
  • De manera similar, al modificar o eliminar elementos DOM anidados , el procesamiento a la inversa puede evitar errores . Por ejemplo, considere la modificación del innerHTML de un nodo padre antes de manejar sus hijos. En el momento en que se llegue al nodo secundario, se desconectará del DOM y será reemplazado por un elemento secundario recién creado cuando se escribió el HTML interno del padre.
  • Es más corto de escribir y leer que algunas de las otras opciones disponibles. Aunque pierde a forEach() y ES6's for ... of .

Desventajas:

  • Procesa los elementos 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 pedido original.
  • La inserción repetida de hermanos en el DOM como primer hijo para conservar su orden es menos eficiente . (El navegador seguiría teniendo que cambiar las cosas correctamente). Para crear nodos DOM de manera eficiente y ordenada, simplemente haga un bucle hacia delante y agregue como de costumbre (y también use un "fragmento de documento").
  • El bucle inverso es confuso para los desarrolladores junior. (Puede considerar que es una ventaja, dependiendo de su perspectiva).

¿Debo usarlo siempre?

Algunos desarrolladores utilizan el modo inverso para el bucle por defecto , a menos que haya una buena razón para hacer un bucle hacia delante.

Aunque las ganancias de rendimiento son generalmente insignificantes, en cierto modo grita:

"Simplemente haga esto a cada elemento de la lista, ¡no me importa el pedido!"

Sin embargo, en la práctica eso no es realmente una indicación confiable de la intención, ya que no se puede distinguir de aquellas ocasiones en las que te preocupas por el orden, y realmente necesitas hacer un giro inverso. Entonces, de hecho, se necesitaría otra construcción para expresar con precisión la intención de "no importa", algo que actualmente no está disponible en la mayoría de los idiomas, incluido ECMAScript, pero que podría llamarse, por ejemplo, para 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), puede ser aceptable usar el bucle inverso para su patrón de ir. Solo recuerde que ver un reverso del bucle en el código existente no significa necesariamente que el orden sea irrelevante.

Es mejor usar forEach ()

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

  • Está claro para leer.
  • Indica que i no se va a desplazar dentro del bloque (lo que siempre es una posible sorpresa que se esconde durante mucho while bucles).
  • Te da un margen 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 vea el reverso del bucle for en 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 avance tradicional para el bucle puede indicar que el cambio puede tener lugar.

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

¿Como funciona?

for (var i = 0; i < array.length; i++) { ... }   // Forwards

for (var i = array.length; i--; )    { ... }   // Reverse

Notará 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. Fundamentalmente, se ejecuta y verifica antes de cada iteración.

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

    Debido a que i-- ejecuta antes de cada iteración, en la primera iteración estaremos accediendo al elemento en array.length - 1 que evita cualquier problema con los elementos undefined matriz fuera de límites .

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

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

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

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

    [5, 5, 4]

    Así que en la iteración final, yo era previamente 1 y la expresión i-- cambia a 0, pero en realidad produce 1 (verdadero), y por lo tanto la condición pasa. En la siguiente iteración, i-- cambia i a -1 pero produce 0 (falsey), lo que hace que la ejecución se salga inmediatamente de la parte inferior del bucle.

    En los forwards de bucle tradicionales, i++ y ++i son intercambiables (como lo señala Douglas Crockford). Sin embargo, a la inversa para el bucle, porque nuestra disminución también es nuestra expresión de condición, debemos mantenernos en i-- si queremos procesar el elemento en el índice 0.

Trivialidades

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


Resumen:

Cuando se recorre una matriz, a menudo podemos querer 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 JS hay muchas maneras de lograr estos dos objetivos. Sin embargo, algunos son más convenientes que otros. A continuación, puede encontrar algunos métodos comúnmente utilizados (la imo más conveniente) para lograr la iteración de matrices en javascript.

Creando nueva matriz: Map

map()es una función ubicada en la Array.prototypeque se puede transformar cada elemento de una matriz y luego se 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 por la función de devolución de llamada que se pasa como un argumento a map().

La diferencia distintiva entre mapy otro mecanismo de bucle como forEachy un for..ofbucle es que mapvuelve como una matriz nueva y deja la matriz antigua intacta (excepto si se manipula explícitamente con la forma en que se piensa splice).

También tenga en cuenta que la mapdevolución de llamada de la función proporciona como segundo argumento el número de índice de la iteración actual. Además, el tercer argumento proporciona la matriz en la que mapse llamó. A veces estas propiedades pueden ser muy útiles.

Bucle usando forEach

forEaches una función que se encuentra en la Array.prototypeque toma una función de devolución de llamada como un argumento. A continuación, ejecuta esta función de devolución de llamada para cada elemento de la matriz. En contraste con 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 como segundo argumento el número de índice de la iteración actual. También proporciona el tercer argumento la matriz en la que forEachse llamó.

Recorrer los elementos usando for..of

El for..ofbucle recorre todos los elementos 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 se elementrefiere a un elemento de matriz y arres la matriz a la que queremos hacer un bucle. No es que el nombre elementsea ​​arbitrario y podríamos haber elegido cualquier otro nombre como 'el' o algo más declarativo cuando sea aplicable.

No confunda el for..inbucle con el for..ofbucle. for..inrecorrerá todas las propiedades enumerables de la matriz, mientras que el for..ofbucle 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);
}


Sé que este es un post antiguo, y ya hay muchas respuestas geniales.Para un poco más de completitud, pensé en lanzar 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 de 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 el

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 la angular.forEachfunción en lugar del forbucle incorporado con sabor a vainilla .

Pros

  • Fácil legibilidad
  • Facilidad de escritura
  • Si está disponible, angular.forEachutilizará el bucle ES5 forEach. Ahora, llegaré a la eficiencia en la sección de 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, 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
        }
    }
}

Concedido, 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 esa materia.

Contras

  • Eficiencia. angular.forEachy el nativo forEach, para el caso, son mucho más lentos que el forbucle normal ... aproximadamente un 90% más lento . Por lo tanto, para grandes conjuntos de datos, es mejor atenerse al forbucle nativo .
  • No hay descanso, continuar, o devolver el soporte. continueEn realidad, está soportado por " accident ", para continuar en una angular.forEachsimple opción, coloque una return;declaración en la función 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 nativo forEachno admite la interrupción o la continuación tampoco.

Estoy seguro de que también hay otras ventajas y desventajas, y por favor siéntase libre de agregar lo que considere oportuno. Siento que, en el fondo, si necesita eficiencia, siga con el forbucle nativo para sus necesidades de bucle. Pero, si tus conjuntos de datos son más pequeños y es bueno renunciar a un poco de eficiencia a cambio de la legibilidad y la capacidad de escritura, entonces, por supuesto, echa un vistazo angular.forEacha ese chico malo.


Si desea realizar un bucle en una matriz, utilice el bucle estándar de tres partes.

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

Puede obtener algunas optimizaciones de rendimiento si almacena en caché myArray.length o lo myArray.length hacia atrás.


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 puede usar shift() que dará y eliminará el primer elemento de y .


Una implementación de 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
  }
);

Edición : Esta respuesta está totalmente fuera de fecha. Para un enfoque más moderno, mira los métodos disponibles en una matriz . Los métodos de interés pueden ser:

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

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

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 tener problemas de rendimiento con este enfoque, ya que recorrerá una gran cantidad de índices que realmente no existen en la matriz. En este caso, un for .. in -loop podría ser una mejor idea. Sin embargo , debe usar los resguardos apropiados para asegurarse de que solo se actúen las propiedades deseadas de la matriz (es decir, los elementos de la matriz), ya que el for..in -loop también se enumerará en los navegadores heredados, o si el adicional Las propiedades 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". El Polyfill para esta funcionalidad es, sin embargo, trivial y como hace que el código sea más fácil de leer, es un buen polyfill para incluir.


TL; DR

  • No lo use for-in menos que lo use con medidas de seguridad o al menos sea consciente de por qué lo puede morder.
  • Tus mejores apuestas suelen ser

    • un bucle for-of (solo ES2015 +),
    • Array#forEach ( spec | MDN ) (o some sus parientes) (solo ES5 +),
    • un simple pasado for moda for bucle,
    • o for-in con salvaguardias.

Pero hay mucho más que explorar, sigue leyendo ...

JavaScript tiene una poderosa semántica para recorrer en forma de arrays y objetos similares a matrices. He dividido la respuesta en dos partes: opciones para arreglos genuinos y opciones para cosas que son como arreglos, como el objeto de arguments , otros objetos iterables (ES2015 +), colecciones DOM, etc.

Notaré rápidamente que puede usar las opciones de ES2015 ahora , incluso en los motores ES5, mediante la transpilación de ES2015 a ES5. Busque por "ES2015 transpiling" / "ES6 transpiling" para más ...

Bien, echemos un vistazo a nuestras opciones:

Para matrices reales

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

  1. Utilice forEach y relacionado (ES5 +)
  2. Usa un simple for bucle.
  3. Utilizar for-in correctamente
  4. Utilice for-of (use un iterador implícitamente) (ES2015 +)
  5. Utilice un iterador explícitamente (ES2015 +)

Detalles:

1. Utilice forEach y relacionado

En cualquier entorno vagamente moderno (por lo tanto, no IE8) donde tenga acceso a las características de Array 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 this cuando se llama a esa devolución de llamada (no se utiliza arriba). Se llama a la devolución de llamada para cada entrada de la matriz, en orden, omitiendo las entradas no existentes en matrices dispersas. Aunque solo usé un argumento arriba, 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 aún no lo tenga a mano) ).

A menos que esté soportando navegadores obsoletos como IE8 (que NetApps muestra con un poco más del 4% de participación de mercado en el momento de este escrito en septiembre de 2016), puede usar forEach en una página web de uso general sin un truco. Si es necesario que admita navegadores obsoletos, el ajuste y el relleno de polietileno para cada forEach se realiza fácilmente (busque "es5 shim" para varias opciones).

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

Si está preocupado por el costo de tiempo de ejecución de realizar una llamada de función para cada entrada de matriz, no lo haga; blog.niftysnippets.org/2012/02/foreach-and-runtime-cost.html

Además, forEach es la función "recorrer todos ellos", pero ES5 definió varias otras funciones útiles de "trabajar a través de la matriz y hacer cosas", que incluyen:

  • every (se detiene en bucle la primera vez que la devolución de llamada devuelve false o algo falso)
  • some (se detiene en bucle la primera vez que la devolución de llamada devuelve true o algo verdadero)
  • filter (crea una nueva matriz que incluye elementos donde la función de filtro devuelve true y omite aquellos en los que devuelve false )
  • map (crea una nueva matriz a partir de los valores devueltos por la devolución de llamada)
  • reduce (acumula un valor invocando repetidamente 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. Usa un simple for bucle.

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 cambia durante el bucle, y está en un código sensible al rendimiento (poco probable), una versión un poco más complicada que tome la longitud por adelantado podría ser un poco más rápida:

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 de JavaScript modernos, es raro que necesites sacar el último trago.

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

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 lo hace, no solo se recrea el value sino también el index para cada iteración de bucle, lo que significa que los cierres creados en el cuerpo del bucle mantienen una referencia al index (y el 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 "El índice es: 0" si hace clic en el primero y "El índice es: 4" si hace clic en el último. Esto no funciona si usas var lugar de let .

3. Use for-in correctamente

Obtendrás personas que te dicen que uses for-in , pero eso no es para lo que es for for-in . for-in recorre las propiedades enumerables de un objeto , no los índices de una matriz. El pedido no está garantizado , ni siquiera en ES2015 (ES6). ES2015 define un orden para las propiedades del objeto (a través de [[OwnPropertyKeys]] , [[Enumerate]] , y las cosas que las usan como Object.getOwnPropertyKeys ), pero no define que la entrada for-in seguirá ese orden. (Detalles en esta otra respuesta .)

Aún así, puede ser útil, particularmente para arreglos dispersos , si usa las medidas de seguridad 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 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 propia propiedad con ese nombre (no uno que 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 por la que es 2 ^ 32 - 2 es que hace que el mayor valor de índice sea inferior a 2 ^ 32 - 1 , que es el valor máximo que puede tener la length una matriz. (Por ejemplo, la longitud de una matriz se ajusta a un entero sin signo de 32 bits). (Los apoyos a RobG por señalar en un comentario en mi publicación del blog que mi prueba anterior no era la correcta).

Eso es un poco de la sobrecarga adicional por iteración de bucle en la mayoría de los arrays, pero si tiene una matriz dispersa , puede ser una forma más eficiente de realizar un bucle porque solo realiza un bucle para las entradas que realmente existen. Por ejemplo, para la matriz anterior, hacemos un bucle un total de tres veces (para las teclas "0" , "10" y "10000" ; recuerde, son cadenas), no 10,001 veces.

Ahora, no querrá escribir eso cada vez, así que puede poner esto en su caja 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 en una prueba de "lo suficientemente bueno 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. Use for-of (use un iterador implícitamente) (ES2015 +)

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

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

Salida:

a
b
c

Debajo de las cubiertas, se obtiene un iterador de la matriz y se recorre a través de él, obteniendo los valores de éste. Esto no tiene el problema que tiene for-in , porque utiliza un iterador definido por el objeto (la matriz), y las matrices definen que sus iteradores se repiten en sus entradas (no en sus propiedades). A diferencia de for-in en ES5, el orden en que se visitan las entradas es el orden numérico de sus índices.

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

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 del iterador en la especificación. Su next método devuelve un nuevo objeto de resultado cada vez que lo llamas. El objeto de resultado tiene una propiedad, done , que nos dice si está hecho y un value propiedad con el valor para esa iteración. ( done es opcional si sería false , el value es opcional si sería undefined ).

El significado del value varía según el iterador; las matrices admiten (al menos) tres funciones que devuelven iteradores:

  • values() : este es el que he usado anteriormente. 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 (por lo tanto, para nuestro anterior, sería "0" , luego "1" , luego "2" ).
  • entries() : devuelve un iterador donde cada value es una matriz en la forma [key, value] para esa iteración.

Para objetos similares a matrices

Aparte de las matrices verdaderas, también hay objetos parecidos a una matriz que tienen propiedades de length y propiedades con nombres numéricos: instancias de NodeList , objeto de arguments , etc. ¿Cómo hacemos un bucle a través de su contenido?

Utilice cualquiera de las opciones anteriores para los arreglos

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

  1. Utilice forEach y relacionado (ES5 +)

    Las diversas funciones en Array.prototype son "genéricamente intencionalmente" y, por lo general, se pueden usar en objetos similares a matrices a través de la Function#call o la Function#apply . (Consulte la advertencia sobre los objetos provistos por el host al final de esta respuesta, pero es un problema poco frecuente).

    Supongamos que desea utilizar forEach en la forEach de un Node . Tu harias esto

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

    Si va a hacer eso mucho, es posible que desee tomar una copia de la referencia de la 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 simple for bucle.

    Obviamente, un simple bucle for aplica a objetos similares a matrices.

  3. Utilizar for-in correctamente

    for-in con las mismas salvaguardas que con una matriz también deberían funcionar con objetos similares a una matriz; puede aplicarse la advertencia para los objetos provistos por el host en el # 1 anterior.

  4. Utilice for-of (use un iterador implícitamente) (ES2015 +)

    for-of usará el iterador proporcionado por el objeto (si lo hay); tendremos que ver cómo se juega con los diversos objetos similares a matrices, particularmente los proporcionados por el host. Por ejemplo, la especificación para el NodeList de querySelectorAll se actualizó para admitir la iteración. La especificación para la HTMLCollection de getElementsByTagName no lo era.

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

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

Crea una verdadera matriz

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

  1. Utilice el método de división de matrices

    Podemos usar el método de división de arreglos, que al igual que los otros métodos mencionados anteriormente es "genéricamente intencionalmente" y, por lo tanto, puede usarse con objetos similares a arreglos, 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"));
    

    Vea la advertencia sobre los objetos provistos por el host a continuación En particular, tenga en cuenta que esto fallará en IE8 y versiones anteriores, lo que no le permitirá usar objetos provistos por el host de this manera.

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

    También es posible utilizar la sintaxis extendida de ES2015 con motores de JavaScript que admiten esta función:

    var trueArray = [...iterableObject];
    

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

    var divs = [...document.querySelectorAll("div")];
    
  3. Utilice Array.from (spec) | (MDN)

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

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

    O si desea obtener una matriz de los nombres de etiqueta de los elementos con una clase dada, 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 los objetos proporcionados por el anfitrión

Si usa las funciones de Array.prototype con objetos similares a arreglos proporcionados por el host (listas DOM y otras cosas proporcionadas por el navegador en lugar del motor de JavaScript), debe asegurarse de probar en sus entornos de destino para asegurarse de que objeto se comporta correctamente. La mayoría se comporta correctamente (ahora), pero es importante probar. La razón es que la mayoría de los métodos de Array.prototype que querrá usar dependerán del objeto proporcionado por el host, que dará una respuesta honesta a la operación abstracta [[HasProperty]] . Al momento de escribir esto, los navegadores hacen un muy buen trabajo con esto, pero la especificación 5.1 permitió la posibilidad de que un objeto provisto por el host no sea honesto. Está en §8.6.2 , varios párrafos debajo de la tabla grande 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 de host particular, efectivamente capturen y almacenen valores de propiedad, pero [[HasProperty]] siempre genera falso .

(No pude encontrar la verborrea equivalente en la especificación ES2015, pero es probable que siga siendo el caso.) Una vez más, a partir de este momento se escriben los objetos comunes de tipo matriz proporcionados por el host en los navegadores modernos [instancias de NodeList , por ejemplo] maneja [[HasProperty]] correctamente, pero es importante probar.)


ECMAScript5 (la versión en Javascript) para trabajar con Arrays.

forEach : itera a través de 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 the #" + (index+1) + " in 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 caso de que, más interesado en la operación en la matriz utilizando alguna característica incorporada.

mapa : crea una nueva matriz con el resultado de la función de devolución de llamada. Este método es bueno para usar cuando necesite 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 currenct 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]

Espero que esto sea de utilidad.


Este es un iterador para la 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'
);

Cada 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 la cadena como función: la función se crea fuera de contexto y debe usarse solo cuando esté seguro del alcance de la variable. De lo contrario, es mejor pasar funciones donde el alcance es más intuitivo.


Puedes llamar a cada uno de esta manera:

let Array = [1,3,2];

theArray.forEach((element)=>{ 
  // use the element of the array
  console.log(element) 
}

El elemento tendrá el valor de cada índice desde 0 hasta la longitud de la matriz.

Salida:

1    
3    
2

Explicacion

forEach está en la clase de prototipo. También puede llamar a esto como theArray.prototype.forEach (...);

prototipo: https://hackernoon.com/prototypes-in-javascript-5bba2990e04b

También puede modificar una matriz como esta:

for(let i=0;i<theArray.length;i++){
  console.log(i); //i will have the value of each index
}

También me gustaría agregar esto como una composición de un bucle inverso y una respuesta anterior para alguien que también quisiera 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í que no será necesario declararlo más adelante con otra línea. Es útil cuando se realiza un bucle a través de la matriz de objetos.

Contras:

Esto se romperá cuando la referencia sea falsa - falsey (indefinido, etc.). Aunque puede ser usado como una ventaja. Sin embargo, sería un poco más difícil de leer. Y también, dependiendo del navegador, puede "no" optimizarse para funcionar más rápido que el original.


Hay tres implementaciones de foreachen jQuery como sigue.

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

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 sobre desbordamiento de pila ¿ Por qué usar "for ... in" con la iteración de matrices es una mala idea? )

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

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á a partir array[0]de array[2]. Primero, esto hará referencia primero a las 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
//!!!

Si quieres usarlo forEach(), se verá como ...

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

Si quieres usarlo for(), se verá como ...

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


Una forma más cercana a su idea sería utilizar la Array.forEach()que acepte una función de clojure que se ejecutará para cada elemento de la matriz.

myArray.forEach(
  (item) => {
    // do something 
    console.log(item);
  }
);

Otra forma viable sería usar lo Array.map()que funciona de la misma manera pero también mutatescada elemento y lo devuelve como:

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

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

Una solución fácil ahora sería utilizar 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

  • Array::forEach .
  • En for_each...in (MDN) se explica que for each (variable in object)está en desuso como parte del estándar ECMA-357 ( EAX ).
  • for...of (MDN) describe la siguiente forma de iteración utilizando for (variable of object)como parte de la propuesta de Harmony (ECMAScript 6).

var a = ["car", "bus", "truck"]
a.forEach(function(item, index) {
    console.log("Index" + index);
    console.log("Element" + item);
})




iteration