javascript - attribute - ¿Por qué document.querySelectorAll devuelve StaticNodeList en lugar de una matriz real?
queryselectorall foreach (5)
Creo que es una decisión filosófica del W3C. El diseño del W3C DOM [spec] es bastante ortogonal al diseño de JavaScript, ya que DOM está destinado a ser plataforma y lenguaje neutral.
Decisiones como " getElementsByFoo()
devuelve un NodeList
ordenado" o " querySelectorAll()
devuelve StaticNodeList
" son muy intencionales, por lo que las implementaciones no tienen que preocuparse de alinear su estructura de datos devuelta basada en implementaciones dependientes del lenguaje (como .map
estando disponible en Arrays en JavaScript y Ruby, pero no en Listas en C #).
El objetivo del W3C es bajo: dirán que una NodeList
debería contener una propiedad .length
de tipo unsigned long porque creen que cada implementación puede al menos soportar eso , pero no dirán explícitamente que el operador de índice []
debería estar sobrecargado a soporte para obtener elementos posicionales, porque no quieren bloquear un poco de lenguaje pobre que viene y quiere implementar getElementsByFoo()
pero no puede soportar la sobrecarga del operador. Es una filosofía prevaleciente presente en gran parte de las especificaciones.
John Resig ha expresado una opción similar a la suya, a la que agrega :
Mi argumento no es tanto que
NodeIterator
no sea muy similar a DOM, sino que no es muy parecido a JavaScript. No aprovecha las características presentes en el lenguaje JavaScript y las usa de la mejor manera posible ...
De alguna manera siento empatía. Si el DOM se escribió específicamente con las características de JavaScript en mente, sería mucho menos incómodo y más intuitivo de usar. Al mismo tiempo entiendo las decisiones de diseño del W3C.
Me molesta que no puedo hacer document.querySelectorAll(...).map(...)
incluso en Firefox 3.6, y todavía no puedo encontrar una respuesta, así que pensé en publicar de forma cruzada en ASÍ la pregunta de este blog:
http://blowery.org/2008/08/29/yay-for-queryselectorall-boo-for-staticnodelist/
¿Alguien sabe de una razón técnica por la que no obtienes un Array? ¿O por qué StaticNodeList no hereda de una matriz de forma que pueda usar map
, concat
, etc.?
(Por cierto, si solo desea una función, puede hacer algo como NodeList.prototype.map = Array.prototype.map;
... pero nuevamente, ¿por qué esta funcionalidad (¿intencionalmente?) Está bloqueada en primer lugar?)
Creo que simplemente puedes hacer lo siguiente
Array.prototype.map.call(document.querySelectorAll(...), function(...){...});
Funciona perfecto para mí
No sé por qué devuelve una lista de nodos en lugar de una matriz, tal vez porque, como getElementsByTagName, actualizará el resultado cuando actualice el DOM. De todos modos, un método muy simple para transformar ese resultado en una matriz simple es:
Array.prototype.slice.call(document.querySelectorAll(...));
y luego puedes hacer:
Array.prototype.slice.call(document.querySelectorAll(...)).map(...);
Puede usar el operador de propagación ES2015 (ES6):
[...document.querySelectorAll(''div'')]
convertirá StaticNodeList en una matriz de elementos.
Aquí hay un ejemplo sobre cómo usarlo.
[...document.querySelectorAll(''div'')].map(x => console.log(x.innerHTML))
<div>Text 1</div>
<div>Text 2</div>
Solo para agregar a lo que Crescent dijo,
si solo desea una función, puede hacer algo como NodeList.prototype.map = Array.prototype.map
No hagas esto! No está garantizado que funcione.
Ningún JavaScript o estándar DOM / BOM especifica que la NodeList
constructor NodeList
existe incluso como una propiedad global / de window
, o que la NodeList
devuelta por querySelectorAll
heredará de ella, o que su prototipo es escribible, o que la función Array.prototype.map
realmente funcionará en una NodeList.
A NodeList se le permite ser un ''objeto host'' (y es uno, en IE y algunos navegadores más antiguos). Los métodos Array
se definen como permitidos para operar en cualquier ''objeto nativo'' de JavaScript que exhiba las propiedades numéricas y de length
, pero no están obligados a trabajar en objetos host (y en IE, no lo hacen).
Es molesto que no obtenga todos los métodos de matriz en listas DOM (todos ellos, no solo StaticNodeList), pero no hay una manera confiable de eludirlo. Tendrá que convertir cada lista DOM que regrese a una matriz manualmente:
Array.fromList= function(list) {
var array= new Array(list.length);
for (var i= 0, n= list.length; i<n; i++)
array[i]= list[i];
return array;
};
Array.fromList(element.childNodes).forEach(function() {
...
});