为什么document.querySelectorAll返回StaticNodeList而不是真正的Array?

时间:2010-04-08 13:47:48

标签: javascript dom css-selectors

我不知道即使在Firefox 3.6中我也不能document.querySelectorAll(...).map(...),我仍然无法找到答案,所以我想我会在这篇博客上交叉发帖:

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

有没有人知道您没有获得阵列的技术原因?或者为什么StaticNodeList不会以可以使用mapconcat等方式从数组继承?

(顺便说一句,如果它只是你想要的一个功能,你可以做NodeList.prototype.map = Array.prototype.map;之类的事情......但是,为什么这个功能(有意??)首先被阻止了?)

7 个答案:

答案 0 :(得分:137)

您可以使用ES2015(ES6)spread operator

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

会将StaticNodeList转换为项目数组。

以下是如何使用它的示例。



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

<div>Text 1</div>
<div>Text 2</div>
&#13;
&#13;
&#13;

答案 1 :(得分:71)

我认为这是W3C的哲学决定。 W3C DOM [spec]的设计与JavaScript的设计完全正交,因为DOM 意味着是平台和语言中立的。

getElementsByFoo()返回有序NodeList”或“querySelectorAll()返回StaticNodeList”等决策非常有意,因此实施不必担心根据依赖于语言的实现来对齐它们返回的数据结构(例如,.map在JavaScript和Ruby中的数组上可用,但<#>不是在C#中的列表中。)

W3C目标很低:他们会说NodeList应该包含readonly .length property of type unsigned long,因为他们认为每个实施都至少可以支持 ,但他们不会说显式地,[]索引运算符应该被重载以支持获取位置元素,因为他们不想阻止一些可能实现getElementsByFoo()但不支持运算符重载的可怜的小语言。在整个规范中,这是一种流行的哲学。

John Resig voiced a similar option为您he adds

  

我的论点不是那么多   NodeIterator不像DOM那样   它不像JavaScript那样。它   没有利用这些功能   以JavaScript语言呈现   尽最大努力使用它们......

我有些同情。如果DOM是专门针对JavaScript功能编写的,那么使用它会更加笨拙且更直观。同时我也了解W3C的设计决策。

答案 2 :(得分:41)

我不知道它为什么返回节点列表而不是数组,可能因为像getElementsByTagName一样,它会在更新DOM时更新结果。无论如何,在简单数组中转换结果的一个非常简单的方法是:

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

然后你可以这样做:

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

答案 3 :(得分:12)

只是为了补充Crescent所说的,

  

如果它只是你想要的一个函数,你可以做类似NodeList.prototype.map = Array.prototype.map

的事情。

不要这样做!完全没有保证能够正常工作。

没有JavaScript或DOM / BOM标准指定NodeList构造函数甚至作为全局/ window属性存在,或NodeList返回的querySelectorAll将继承它,或者它的原型是可写的,或者函数Array.prototype.map实际上可以在NodeList上工作。

允许NodeList成为“主机对象”(在IE和一些旧版浏览器中是一个)。 Array方法被定义为允许对任何暴露数字和length属性的JavaScript“本机对象”进行操作,但它们不需要在宿主对象上工作(在IE中,它们不会“T)。

令人讨厌的是你没有获得DOM列表上的所有数组方法(所有这些方法,而不仅仅是StaticNodeList),但是它没有可靠的方法。您必须手动转换回到阵列的每个DOM列表:

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

答案 4 :(得分:1)

我认为您可以简单地执行以下操作

public class Configuration
{
    [Key]
    public int ClientId { get; set; }

    public CommunicationType CommunicationType { get; set; }

    public string CommunicationValue { get; set; }

    [ForeignKey("ClientId")]
    public virtual Client Client { get; set; }
}

它对我来说很完美

答案 5 :(得分:0)

Array.from(document.querySelectorAll(...)).map(...)

在 IE11 上不可用 https://caniuse.com/?search=from

答案 6 :(得分:-1)

这是我想添加到此处其他人建议的其他可能性范围内的一个选项。它仅是出于智力上的乐趣,不建议


仅仅为了它的乐趣,这是一种“强迫” querySelectorAll下跪并向你鞠躬的方法:

Element.prototype.querySelectorAll = (function(QSA){
    return function(){
        return [...QSA.call(this, arguments[0])]
    }
})(Element.prototype.querySelectorAll);

现在,逐步执行该功能感觉很好,向谁表明是谁是老板。 现在,我不知道有什么更好的方法,创建一个全新的 named 函数包装器,然后让您的所有代码都使用该怪异的名称(几乎是jQuery样式),或者一次重写上面的函数,其余您的代码仍然可以使用原始DOM方法名称querySelectorAll

  

除非您诚实地不给[您知道什么],否则我不会以任何方式推荐它。