JavaScript - Matices de myArray.forEach vs for loop


88

He visto muchas preguntas que sugieren usar:

for (var i = 0; i < myArray.length; i++){ /* ... */ }

en vez de:

for (var i in myArray){ /* ... */ }

para matrices, debido a iteraciones inconsistentes ( ver aquí ).


Sin embargo, parece que no puedo encontrar nada que parezca preferir el bucle orientado a objetos:

myArray.forEach(function(item, index){ /* ... */ });

Lo que me parece mucho más intuitivo.

Para mi proyecto actual, la compatibilidad con IE8 es importante y estoy considerando usar el polyfill de Mozilla , sin embargo, no estoy 100% seguro de cómo funcionará.

  • ¿Existen diferencias entre el bucle for estándar (el primer ejemplo anterior) y la implementación Array.prototype.forEach de los navegadores modernos?
  • ¿Existe alguna diferencia entre las implementaciones de navegadores modernos y la implementación de Mozilla vinculada anteriormente (con especial atención a IE8)?
  • El rendimiento no es un problema, solo la coherencia con las propiedades que se repiten.

6
No es posible breaksalir forEach. Pero una gran ventaja es crear un nuevo alcance con la función. Con el polyfill no deberías tener ningún problema (al menos no he encontrado ninguno).
hgoebl

Los problemas que puede tener con IE más antiguos no es el shim en sí, sino el constructor de matriz roto / literal wrt holesdonde undefineddebería estar y otros métodos rotos, como slicey hasOwnPropertywrt para objetos DOM tipo matriz. Mis pruebas y es5 shimhan demostrado que dichos métodos con calce cumplen con la especificación (no se probó el calzo de MDN).
Xotic750

1
Y para romper un forbucle, para eso es some.
Xotic750

1
"Sin embargo, parece que no puedo encontrar nada que parezca preferir el bucle orientado a objetos:" Prefiero llamarlo forma funcional frente a imperativo.
Memke

Puede utilizar Array.find()para salir del bucle después de encontrar una primera coincidencia.
Mottie

Respuestas:


122

La diferencia más sustancial entre el forbucle y el forEachmétodo es que, con el primero, puede breaksalir del bucle. Puede simular continuesimplemente regresando de la función pasada a forEach, pero no hay forma de detener el bucle por completo.

Aparte de eso, los dos logran efectivamente la misma funcionalidad. Otra diferencia menor involucra el alcance del índice (y todas las variables que lo contienen) en el ciclo for, debido a la elevación de variables.

// 'i' is scoped to the containing function
for (var i = 0; i < arr.length; i++) { ... }

// 'i' is scoped to the internal function
arr.forEach(function (el, i) { ... });

Sin embargo, encuentro que forEaches mucho más expresivo: representa su intención de iterar a través de cada elemento de una matriz y le proporciona una referencia al elemento, no solo al índice. En general, todo se reduce al gusto personal, pero si puede usarlo forEach, le recomendaría usarlo.


Hay algunas diferencias más sustanciales entre las dos versiones, específicamente con respecto al rendimiento. De hecho, el bucle for simple funciona considerablemente mejor que el forEachmétodo, como lo demuestra esta prueba jsperf .

Si tal actuación es necesaria o no para usted, depende de usted decidir y, en la mayoría de los casos, preferiría la expresividad a la velocidad. Esta diferencia de velocidad probablemente se deba a las diferencias semánticas menores entre el bucle básico y el método cuando se opera en matrices dispersas, como se indica en esta respuesta .

Si no necesita el comportamiento de forEachy / o necesita salir del ciclo temprano, puede usar Lo-Dash _.eachcomo alternativa, que también funcionará en todos los navegadores. Si está utilizando jQuery, también proporciona un similar$.each , solo tenga en cuenta las diferencias en los argumentos pasados ​​a la función de devolución de llamada en cada variación.

(En cuanto al forEachpolyfill, debería funcionar en navegadores más antiguos sin problemas, si elige seguir esa ruta).


1
Vale la pena señalar que las versiones de la biblioteca eachno se comportan de la misma manera que la especificación ECMA5 de forEach, tienden a tratar todas las matrices como densas (para evitar errores de IE, siempre que lo sepa). De lo contrario, puede ser un "gotcha". Como referencia github.com/es-shims/es5-shim/issues/190
Xotic750

7
También hay algunos métodos de prototipo que le permiten romper, como el Array.prototype.someque se repetirá hasta que devuelva un valor verdadero o hasta que haya recorrido completamente la matriz. Array.prototype.everyes similar a, Array.prototype.somepero se detiene si devuelve un valor falso.
axelduch

Si desea ver algún resultado de prueba en diferentes navegadores y tales calzas, puede echar un vistazo aquí, ci.testling.com/Xotic750/util-x
Xotic750

Además, usar Array.prototype.forEach pondría su código a merced de la extensión. Por ejemplo, si está escribiendo un código para incrustarlo en una página, existe la posibilidad de que Array.prototype.forEach se sobrescriba con algo más.
Marble Daemon

2
@MarbleDaemon La posibilidad de eso es tan minúscula que es efectivamente imposible y, por lo tanto, insignificante. Sobrescribir Array.prototype.forEachcon alguna versión no compatible tendría el potencial de romper tantas bibliotecas que evitarlo por esa razón no ayudaría, de todos modos.
Alexis King

12

Puede usar su función foreach personalizada, que funcionará mucho mejor que Array.forEach

Debería agregar esto una vez a su código. Esto agregará una nueva función a la matriz.

function foreach(fn) {
    var arr = this;
    var len = arr.length;
    for(var i=0; i<len; ++i) {
        fn(arr[i], i);
    }
}

Object.defineProperty(Array.prototype, 'customForEach', {
    enumerable: false,
    value: foreach
});

Entonces puede usarlo en cualquier lugar como Array.forEach

[1,2,3].customForEach(function(val, i){

});

La única diferencia es que es 3 veces más rápido. https://jsperf.com/native-arr-foreach-vs-custom-foreach

ACTUALIZACIÓN: En la nueva versión de Chrome, se mejoró el rendimiento de .forEach (). Sin embargo, la solución puede ofrecer un rendimiento adicional en otros navegadores.

JSPerf


4

Muchos desarrolladores (por ejemplo, Kyle Simpson) sugieren usarlo .forEachpara indicar que la matriz tendrá un efecto secundario y .mappara funciones puras. forLos bucles se adaptan bien como una solución de propósito general para un número conocido de bucles o cualquier otro caso que no encaja, ya que es más fácil de comunicarse debido a su amplio soporte en la mayoría de los lenguajes de programación.

p.ej

/* For Loop known number of iterations */
const numberOfSeasons = 4;
for (let i = 0; i < numberOfSeasons; i++) {
  //Do Something
}

/* Pure transformation */
const arrayToBeUppercased = ['www', 'html', 'js', 'us'];
const acronyms = arrayToBeUppercased.map((el) => el.toUpperCase));

/* Impure, side-effects with .forEach */
const acronymsHolder = [];
['www', 'html', 'js', 'us'].forEach((el) => acronymsHolder.push(el.toUpperCase()));

En cuanto a las convenciones, esto parece lo mejor, sin embargo, la comunidad realmente no se ha conformado con una convención sobre los for inbucles de protocolo de iteración más nuevos . En general, creo que es una buena idea seguir los conceptos de FP que la comunidad de JS parece estar abierta a adoptar.

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.