for - find object in array javascript
¿Para cada uno sobre una matriz en JavaScript? (28)
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 conarray.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''sfor ... 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 enarray.length - 1
que evita cualquier problema con los elementosundefined
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 operadori
final disminuyei
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 eni--
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.
¿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.
Resumen:
Cuando se recorre una matriz, a menudo podemos querer lograr uno de los siguientes objetivos:
Queremos iterar sobre la matriz y crear una nueva matriz:
Array.prototype.map
Queremos iterar sobre la matriz y no crear una nueva matriz:
Array.prototype.forEach
for..of
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.prototype
que 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 map
y otro mecanismo de bucle como forEach
y un for..of
bucle es que map
vuelve 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 map
devolució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 map
se llamó. A veces estas propiedades pueden ser muy útiles.
Bucle usando forEach
forEach
es una función que se encuentra en la Array.prototype
que 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 map
función, la forEach
devolució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 forEach
se llamó.
Recorrer los elementos usando for..of
El for..of
bucle 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 element
refiere a un elemento de matriz y arr
es la matriz a la que queremos hacer un bucle. No es que el nombre element
sea arbitrario y podríamos haber elegido cualquier otro nombre como ''el'' o algo más declarativo cuando sea aplicable.
No confunda el for..in
bucle con el for..of
bucle. for..in
recorrerá todas las propiedades enumerables de la matriz, mientras que el for..of
bucle 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);
}
Algunos C estilo C usan foreach
para recorrer las enumeraciones. En JavaScript esto se hace con la estructura de bucle for..in
:
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 los 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 método forEach
a Array.prototype
que se puede usar para enumerar sobre una matriz usando un calback (el polyfill está en los documentos, por lo que aún puede usarlo para navegadores antiguos):
arr.forEach(function (val, index, theArray) {
//do stuff
});
Es importante tener en cuenta que Array.prototype.forEach
no se rompe cuando la devolución de llamada devuelve false
. jQuery y Underscore.js proporcionan sus propias variaciones en each
para proporcionar bucles que pueden cortocircuitarse.
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.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 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.forEach
función en lugar del for
bucle incorporado con sabor a vainilla .
Pros
- Fácil legibilidad
- Facilidad de escritura
- Si está disponible,
angular.forEach
utilizará 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.forEach
y el nativoforEach
, para el caso, son mucho más lentos que elfor
bucle normal ... aproximadamente un 90% más lento . Por lo tanto, para grandes conjuntos de datos, es mejor atenerse alfor
bucle nativo . - No hay descanso, continuar, o devolver el soporte.
continue
En realidad, está soportado por " accident ", para continuar en unaangular.forEach
simple opción, coloque unareturn;
declaración en la funciónangular.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 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 for
bucle 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.forEach
a 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 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].
}
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
}
);
A partir de ES6:
list = [0, 1, 2, 3]
for (let obj of list) {
console.log(obj)
}
Donde of
evita las rarezas asociadas con in
y hace que funcione como el for
bucle de cualquier otro idioma, y se let
enlaza i
dentro del bucle en lugar de dentro de la función.
Las llaves ( {}
) se pueden omitir cuando solo hay un comando (por ejemplo, en el ejemplo anterior).
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
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"):
- Utilice
forEach
y relacionado (ES5 +) - Usa un simple
for
bucle. - Utilizar
for-in
correctamente - Utilice
for-of
(use un iterador implícitamente) (ES2015 +) - 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 devuelvefalse
o algo falso) -
some
(se detiene en bucle la primera vez que la devolución de llamada devuelvetrue
o algo verdadero) -
filter
(crea una nueva matriz que incluye elementos donde la función de filtro devuelvetrue
y omite aquellos en los que devuelvefalse
) -
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
(comoreduce
, 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:
Que el objeto tiene su propia propiedad con ese nombre (no uno que hereda de su prototipo), y
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 cadavalue
es la entrada de la matriz para esa iteración ("a"
,"b"
y"c"
en el ejemplo anterior). -
keys()
: devuelve un iterador donde cadavalue
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 cadavalue
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:
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 laFunction#call
o laFunction#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 laforEach
de unNode
. Tu harias estoArray.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` });
Usa un simple
for
bucle.Obviamente, un simple bucle
for
aplica a objetos similares a matrices.Utilizar
for-in
correctamentefor-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.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 elNodeList
dequerySelectorAll
se actualizó para admitir la iteración. La especificación para laHTMLCollection
degetElementsByTagName
no lo era.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:
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.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")];
Utilice
Array.from
(spec) | (MDN)Array.from
(ES2015 +, pero fácilmenteArray.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.)
Usando Loops con ES6 destructuring y extendiendo el operador.
La destrucción y el uso del operador de propagación han demostrado ser muy útiles para los recién llegados a ES6 por ser más legibles / humanos, aunque algunos veteranos de javascript pueden considerar que es desordenado, los juniors o algunas otras personas pueden encontrarlo útil.
Los siguientes ejemplos utilizarán
for...of
declaración y.forEach
método.Ejemplos 6, 7 y 8 se pueden utilizar con cualquier bucles funcionales como
.map
,.filter
,.reduce
,.sort
,.every
,.some
, para más información acerca de estos métodos visita el objeto de matriz .
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 a key
yvalue
// 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 propiedades de 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 parenthesis
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);
});
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.
La sintaxis lambda no suele funcionar en IE 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);
});
If you are a jQuery Fan and already have a jQuery file running, you should reverse the positions of the index and value parameters
$("#ul>li").each(function(**index,value**){
console.log("value of the looped element" + value);
console.log("index of the looped element" + index);
});
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 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 bucles
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 - loop mientras que una condición es completa. Parece ser el bucle 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, sino que se utiliza si usted tiene 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 la programación funcional en arreglos, consulte la publicación del blog Programación funcional en JavaScript: mapear, filtrar y reducir .
Hay tres implementaciones de foreach
en 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 each
bucle en JavaScript nativo . Puede usar bibliotecas para obtener esta funcionalidad (recomiendo Underscore.js ), use un for
bucle simple .
for (var instance in objects) {
...
}
Sin embargo, tenga en cuenta que puede haber razones para usar un for
bucle 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];
...
}
No hay una habilidad incorporada para entrar forEach
. Para interrumpir la ejecución use el Array#some
siguiente a continuación:
[1,2,3].some(function(number) {
return number === 1;
});
Esto funciona porque some
devuelve verdadero tan pronto como cualquiera de las devoluciones de llamada, ejecutadas en orden de matriz, devuelve verdadero, cortocircuitando la ejecución del resto. Respuesta original ver prototipo de Array para some
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); }
Si tienes una matriz masiva, debes usarla iterators
para ganar algo de eficiencia. Los iteradores son una propiedad de ciertas colecciones de JavaScript (como Map
, Set
, String
, Array
). Incluso, for...ofutiliza iterator
bajo el capó.
Los iteradores mejoran la eficiencia al permitirle consumir los elementos en una lista de uno en uno como si fueran un flujo. Lo que hace especial a un iterador es cómo atraviesa una colección. Otros bucles deben cargar la colección completa por adelantado para iterar sobre ella, mientras que un iterador solo necesita conocer la posición actual en la colección.
Se accede al elemento actual llamando al next
método del iterador . El siguiente método devolverá el value
elemento actual y a boolean
para indicar cuándo ha llegado al final de la colección. El siguiente es un ejemplo de creación de un iterador a partir de una matriz.
Transforma tu matriz regular a 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 a iterador usando Symbol.iterator
así:
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 array
en una iteratorscomo esta:
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 están
iterable
por defecto. Utilízalofor..in
en ese caso porque en lugar de valores funciona con claves.
Puedes leer más sobre iteration protocol
here .
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 mutates
cada 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 each
y delegará automáticamente 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
- 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).
forma jQuery utilizando $.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];
var a = ["car", "bus", "truck"]
a.forEach(function(item, index) {
console.log("Index" + index);
console.log("Element" + item);
})