151 votes

Pourquoi document.querySelectorAll renvoie-t-il une StaticNodeList plutôt qu'un véritable tableau ?

Cela m'ennuie de ne pas pouvoir le faire. document.querySelectorAll(...).map(...) même dans Firefox 3.6, et je n'ai toujours pas trouvé de réponse, alors j'ai pensé poster la question sur SO à partir de ce blog :

http://blowery.org/2008/08/29/yay-for-queryselectorall-boo-for-staticnodelist/

Quelqu'un connaît-il une raison technique pour laquelle vous ne recevez pas d'Array ? Ou pourquoi une StaticNodeList n'hérite pas d'un tableau de manière à ce que vous puissiez utiliser map , concat etc.

(Si vous ne voulez qu'une seule fonction, vous pouvez faire quelque chose comme NodeList.prototype.map = Array.prototype.map; ...mais encore une fois, pourquoi cette fonctionnalité est-elle (intentionnellement ?) bloquée en premier lieu ?)

316voto

Vlad Bezden Points 5024

Vous pouvez utiliser ES2015 (ES6) opérateur de diffusion :

[...document.querySelectorAll('div')]

convertira StaticNodeList en tableau d'éléments.

Voici un exemple d'utilisation.

[...document.querySelectorAll('div')].map(x => console.log(x.innerHTML))

<div>Text 1</div>
<div>Text 2</div>

100voto

Crescent Fresh Points 54070

Je pense qu'il s'agit d'une décision philosophique du W3C. La conception du DOM [spec] du W3C est tout à fait orthogonale à la conception de JavaScript, puisque le DOM est signifié pour être neutre du point de vue de la plate-forme et de la langue.

Des décisions telles que " getElementsByFoo() renvoie un NodeList " ou " querySelectorAll() renvoie un StaticNodeList "sont tout à fait intentionnels, afin que les implémentations n'aient pas à se soucier d'aligner leur structure de données renvoyée en fonction des implémentations dépendantes de la langue (comme .map disponible sur les tableaux en JavaScript et Ruby, mais no sur les listes en C#).

Le W3C vise bas : il dira qu'un NodeList doit contenir un en lecture seule .length propriété de type unsigned long parce qu'ils pensent que toute mise en œuvre peut au moins soutenir que mais ils ne diront pas explicitement que la [] devrait être surchargé pour permettre l'obtention d'éléments positionnels, parce qu'ils ne veulent pas bloquer un pauvre petit langage qui viendrait à se développer et qui voudrait implémenter la fonction getElementsByFoo() mais ne peut pas prendre en charge la surcharge de l'opérateur. Il s'agit d'une philosophie prédominante dans la plupart des spécifications.

John Resig a a exprimé une option similaire comme la vôtre, à laquelle il ajoute :

Mon argument n'est pas tant que cela NodeIterator n'est pas très DOM, c'est qu'il n'est pas très semblable à JavaScript. Il ne n'exploite pas les fonctionnalités présentes dans le langage JavaScript et et ne les utilise pas au mieux de ses capacités...

Je compatis quelque peu. Si le DOM avait été écrit spécifiquement avec les caractéristiques du JavaScript à l'esprit, il serait beaucoup moins gênant et plus intuitif à utiliser. En même temps, je comprends les décisions du W3C en matière de conception.

43voto

mck89 Points 8661

Je ne sais pas pourquoi il retourne une liste de noeuds au lieu d'un tableau, peut-être parce que, comme getElementsByTagName, il mettra à jour le résultat lorsque vous mettrez à jour le DOM. Quoi qu'il en soit, une méthode très simple pour transformer ce résultat en un simple tableau est la suivante :

Array.prototype.slice.call(document.querySelectorAll(...));

et ensuite vous pouvez le faire :

Array.prototype.slice.call(document.querySelectorAll(...)).map(...);

13voto

bobince Points 270740

Juste pour compléter ce qu'a dit Crescent,

si vous ne voulez qu'une seule fonction, vous pouvez faire quelque chose comme NodeList.prototype.map = Array.prototype.map

Ne faites pas cela ! Il n'est pas du tout garanti que cela fonctionne.

Aucune norme JavaScript ou DOM/BOM ne spécifie que l'élément NodeList existe même en tant que fonction-constructeur globale/ window ou que le NodeList renvoyée par querySelectorAll en héritera, ou que son prototype est accessible en écriture, ou que la fonction Array.prototype.map fonctionnera en fait sur une liste de nœuds.

Une liste de nœuds peut être un "objet hôte" (et c'est le cas dans IE et certains navigateurs plus anciens). La liste de nœuds Array sont définies comme étant autorisées à opérer sur tout "objet natif" JavaScript qui expose des données numériques et des données length mais elles ne sont pas tenues de fonctionner sur les objets hôtes (et dans IE, elles ne le font pas).

Il est ennuyeux de ne pas avoir toutes les méthodes de tableau sur les listes DOM (toutes, pas seulement StaticNodeList), mais il n'y a pas de moyen fiable de contourner ce problème. Vous devrez convertir manuellement chaque liste DOM que vous obtiendrez en tableau :

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() {
    ...
});

13voto

apflieger Points 88
Array.from(document.querySelectorAll(...)).map(...)

Pas disponible sur IE11 https://caniuse.com/mdn-javascript_builtins_array_from

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X