javascript - parse - Para bucle para elementos HTMLCollection
queryselectorall (10)
Estoy tratando de establecer el ID de todos los elementos en una colección HTMLC. Escribí el siguiente código:
var list= document.getElementsByClassName("events");
console.log(list[0].id); //first console output
for (key in list){
console.log(key.id); //second console output
}
Pero tengo la salida de follwo en la consola:
event1
undefined
que no es lo que esperaba. ¿Por qué la second console output
undefined
pero la first console output
es event1
?
A partir de marzo de 2016, en Chrome 49.0, for...of
trabajos para HTMLCollection
:
this.headers = this.getElementsByTagName("header");
for (var header of this.headers) {
console.log(header);
}
Vea aquí la documentación .
Pero solo funciona si aplica la siguiente solución alternativa antes de usar el for...of
:
HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
Lo mismo es necesario para usar for...of
con NodeList
:
NamedNodeMap.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
Creo / espero for...of
pronto funcionará sin la solución anterior. El tema abierto está aquí:
https://bugs.chromium.org/p/chromium/issues/detail?id=401699
Actualización: vea el comentario de Expenzor a continuación: Este problema se solucionó a partir de abril de 2016. No es necesario agregar HTMLCollection.prototype [Symbol.iterator] = Array.prototype [Symbol.iterator]; iterar sobre una colección HTM con for ... of
Eeek No debe iterar sobre una lista de nodeList
o HTMLCollection
con for/in
y cuando lo haga, debe recuperar el valor de la lista, usando el índice en su iteración.
En ES5 (y compatible con cualquier cosa posterior), puedes iterar así:
var list= document.getElementsByClassName("events");
for (var i = 0; i < list.length; i++) {
console.log(list[i].id); //second console output
}
for/in
está pensado para iterar las propiedades de un objeto. No está pensado para iterar una matriz o un objeto similar a una matriz que es una colección HTMLC. Solo probé esto en Chrome e iterándolo de la forma en que lo estabas iterando recuperará los elementos de la lista (índices 0, 1, 2, etc.), pero también recuperará la length
y las propiedades del item
. La iteración for/in
simplemente no funcionará para una HTMLCollection.
Consulte http://jsfiddle.net/jfriend00/FzZ2H/ para http://jsfiddle.net/jfriend00/FzZ2H/ por qué no puede iterar una colección HTM con for/in
.
En Firefox, tu for/in
iteration devolvería estos elementos (todas las propiedades iterables del objeto):
0
1
2
item
namedItem
@@iterator
length
Con suerte, ahora puede ver por qué quiere usar for (var i = 0; i < list.length; i++)
lugar, así que solo obtiene 0
, 1
y 2
en su iteración.
Actualización para ES6 en 2015
Agregado a ES6 está Array.from()
que convertirá una estructura similar a una matriz en una matriz real. Eso permite enumerar una lista directamente como esta:
"use strict";
Array.from(document.getElementsByClassName("events")).forEach(function(item) {
console.log(item.id);
});
Demostración de trabajo (en Firefox, Chrome y Edge a partir de abril de 2016): https://jsfiddle.net/jfriend00/8ar4xn2s/
Actualización para ES6 en 2016
Ahora puede usar el ES6 para / de construcción con un NodeList
y una HTMLCollection
simplemente agregando esto a su código:
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
Entonces, puedes hacer:
var list = document.getElementsByClassName("events");
for (var item of list) {
log(item.id);
}
Esto funciona en la versión actual de Chrome, Firefox y Edge.
Demostración de trabajo: http://jsfiddle.net/jfriend00/joy06u4e/ .
Segunda actualización para ES6 en diciembre de 2016
A partir de diciembre de 2016, el soporte de Symbol.iterator
se ha incorporado en Chrome v54 y Firefox v50, por lo que el siguiente código funciona por sí solo. Todavía no está incorporado para Edge.
var list = document.getElementsByClassName("events");
for (let item of list) {
log(item.id);
}
Demostración de trabajo (en Chrome y Firefox): http://jsfiddle.net/jfriend00/3ddpz8sp/
Tercera actualización para ES6 en diciembre de 2017
A partir de diciembre de 2017, esta capacidad funciona en Edge 41.16299.15.0 para una lista de nodeList
como en document.querySelectorAll()
, pero no en HTMLCollection
como en document.getElementsByClassName()
por lo que debe asignar manualmente el iterador para usarlo en Edge Una HTMLCollection
. Es un misterio total por qué arreglarían un tipo de colección, pero no el otro. Pero, al menos puede usar el resultado de document.querySelectorAll()
con ES6 for/of
sintaxis en las versiones actuales de Edge ahora.
También he actualizado el jsFiddle anterior para que compruebe tanto HTMLCollection
como nodeList
separado y capture la salida en el jsFiddle mismo.
Cuarta actualización para ES6 en marzo de 2018
Por mesqueeeb, el soporte de Symbol.iterator
se ha incorporado a Safari, por lo que puede usar for (let item of list)
para document.getElementsByClassName()
o document.querySelectorAll()
.
Quinta actualización para ES6 en abril de 2018
Aparentemente, el soporte para iterar una HTMLCollection
con for/of
vendrá a Edge 18 en otoño de 2018.
Sexta actualización para ES6 en noviembre de 2018
Puedo confirmar que con Microsoft Edge v18 incluido en la actualización de Windows de otoño de 2018, ahora puede iterar tanto una HTMLCollection como una NodeList para / of en Edge.
En ES6, podrías hacer algo como [...collection]
, o Array.from(collection)
,
let someCollection = document.querySelectorAll(someSelector)
[...someCollection].forEach(someFn)
//or
Array.from(collection).forEach(someFn)
La alternativa a Array.from
es usar Array.prototype.forEach.call
forEach: Array.prototype.forEach.call(htmlCollection, i => { console.log(i) });
mapa: Array.prototype.map.call(htmlCollection, i => { console.log(i) });
ect ...
Nervioso
if(!NodeList.prototype.forEach) {
NodeList.prototype.forEach = function(fn, scope) {
for(var i = 0, len = this.length; i < len; ++i) {
fn.call(scope, this[i], i, this);
}
}
}
No hay ninguna razón para usar las funciones de es6 para escapar for
bucle si estás en IE9 o superior.
En ES5, hay dos buenas opciones. Primero, puede "pedir prestado" el Array
para cada forEach
como evan menciones .
Pero aún mejor ...
Use Object.keys()
, que tiene forEach
Object.keys
es esencialmente equivalente a hacer un for... in
con un HasOwnProperty
, pero es más suave.
var eventNodes = document.getElementsByClassName("events");
Object.keys(eventNodes).forEach(function (key) {
console.log(eventNodes[key].id);
});
No puede usar for
/ in
en NodeList
o HTMLCollection
s. Sin embargo, puede usar algunos métodos de Array.prototype
, siempre que los .call()
y pase la NodeList
o HTMLCollection
como this
.
Así que considere lo siguiente como una alternativa a jfriend00''s for
loop :
var list= document.getElementsByClassName("events");
[].forEach.call(list, function(el) {
console.log(el.id);
});
Hay un buen artículo sobre MDN que cubre esta técnica. Tenga en cuenta su advertencia sobre la compatibilidad del navegador sin embargo:
[...] pasar un objeto host (como un
NodeList
) a un método nativo (comoforEach
) no se garantiza que funcione en todos los navegadores y se sabe que falla en algunos.
Entonces, si bien este enfoque es conveniente, un bucle for
puede ser la solución más compatible con el navegador.
Actualización (30 de agosto de 2014): ¡ Eventualmente podrás usar ES6 for
/ of
!
var list = document.getElementsByClassName("events");
for (el of list)
console.log(el.id);
Ya es compatible con las versiones recientes de Chrome y Firefox.
Puedes agregar estas dos líneas:
HTMLCollection.prototype.forEach = Array.prototype.forEach;
NodeList.prototype.forEach = Array.prototype.forEach;
HTMLCollection es devuelto por getElementsByClassName y getElementsByTagName
NodeList es devuelto por querySelectorAll
Así puedes hacer un forEach:
var selections = document.getElementsByClassName(''myClass'');
/* alternative :
var selections = document.querySelectorAll(''.myClass'');
*/
selections.forEach(function(element, i){
//do your stuffs
});
Quieres cambiarlo a
var list= document.getElementsByClassName("events");
console.log(list[0].id); //first console output
for (key in list){
console.log(list[key].id); //second console output
}
Tuve un problema al usar forEach en IE 11 y también en Firefox 49
He encontrado una solución como esta
Array.prototype.slice.call(document.getElementsByClassName("events")).forEach(function (key) {
console.log(key.id);
}