在Javascript中,将NodeList转换为数组的最佳方法是什么


82

DOM方法document.querySelectorAll()(以及其他一些方法)返回NodeList

要对列表进行操作(例如使用)forEach()NodeList必须首先将转换为Array

将转换为的最佳方法NodeListArray什么?


1
我认为querySelectorAll()的返回值在技术上称为NodeList。
jfriend00 2011年

来自mdm “ elementList = document.querySelectorAll(selectors);”
cc年轻的

1
elementList是变量名。该页面描述了返回值的类型如何为NodeList。
jfriend00 2011年

感谢您的更正-已解决问题
cc年轻的

Answers:


67

使用ES6,您可以简单地执行以下操作:

const spanList = [...document.querySelectorAll("span")];

这给了我Type 'NodeListOf<Element>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
回调

@callback,您好,这似乎是与TypeScript相关的错误。您可能选择了以es6编译为目标,而未在tsconfig文件的lib数组中添加“ es6”。问候
Freezystem

1
嗨@Freezystem,您说对了!我的目标是es2015。谢谢!
回调

@callback ES6和ES2015是同一回事
DarkNeuron

65

使用ES6,您可以使用Array.from(myNodeList)。然后使用您喜欢的数组方法。

var myNodeList = document.querySelectorAll('.my-selector');

// ALT 1
Array.from(myNodeList).forEach(function(el) {
  console.log(el);
});

使用ES6填充程序也可以在较旧的浏览器中实现此功能。


如果您使用的是Transpiler(例如Babel),则还有两种选择:

var myNodeList = document.querySelectorAll('.my-selector');

// ALT 2
for (var el of myNodeList) {
  el.classList.add('active'); // or some other action
}

// ALT 3
[...myNodeList].forEach((el) => {
  console.log(el);
});

在es6下,nodeList提供了迭代器也是不正确的吗?
cc年轻的

4
@ccyoung,但是迭代器在不兼容的ES6浏览器中不起作用,因为您无法填充Symbol对象,因此最好使用Array.from(myNodeList)它,因为它可以填充垫片。
Roc

所以我有这个问题,其中Array.from(el.childNodes)不返回第一个节点作为数组的一部分。
zinoadidi

49

您可以使用原型中的slice方法将其转换为数组Array

var elList = document.querySelectorAll('.viewcount');
elList = Array.prototype.slice.call(elList, 0);

此外,如果您需要的只是forEach,则可以从原型中调用Array,而无需先将其强制转换为数组:

var elList = document.querySelectorAll('.viewcount');
Array.prototype.forEach.call(elList, function(el) {
    console.log(el);
});

在ES6中,可以使用新Array.from函数将其转换为数组:

Array.from(elList).forEach(function(el) {
    console.log(el);
});

当前仅在最先进的浏览器中使用,但是如果您使用的是polyfill服务,则可以全面使用此功能。


如果您使用的是ES6转译器,则甚至可以使用for..of循环:

for (var element of document.querySelectorAll('.some .elements')) {
  // use element here
}

谢谢。在较新的javascript思想/希望下,有一个更简洁的强制。
cc年轻的

6
@cc young-请注意,我使用Array.prototype.forEach而不是的原因[].forEach是因为后者创建了一个新的Array对象,这完全没有必要。
约瑟夫·西尔伯

@JosephSilber啊,谢谢-那是创建的新数组是空的[]吗?我的想法是,它将收集垃圾并且对内存的影响可以忽略不计,有人对此发表评论吗?
Daniel Sokolowski15年

@Daniel这是正确的,但是仍然存在创建和销毁数组的计算。
Brett 2015年

21

为什么要转换?-仅call在元素集合上直接使用Array的功能;)

[].forEach.call( $('a'), function( v, i) {
    // do something
});

当然,假设$是您的querySelectorAll别名


编辑:ES6允许使用更短的语法[...$('a')]仅适用于Firefox,截至2014年5月


假设$querySelectorAll
2011年

3
您的答案暗示了jQuery的用法。在这种情况下,由于,完全不需要进行伪造.each()
Matt Ball

1
哈哈哈,为什么 ?没有什么可以阻止您使用别名function $ ( s ) { return document.querySelectorAll(s); }
2011年

5
如果要使用jQuery,$('a').each(function(i, v) {...});
则更简洁的

2
题外话
2011年

9

一定要forEach吗?您可以简单地使用for循环遍历列表:

for (var i = 0; i < elementList.length; i++) {
    doSomethingWith(elementlist.item(i));
}

1
+1是一种简单的解决方案,它不会添加不必要的数组转换。仅供参考,elementList.item(i)您可以使用代替elementList[i]
jfriend00 2011年

4
我个人觉得forEach()更好的编程风格和较少的冗长-ymmv
cc young

@cc young:实际上,我同意你的看法。除非出现这种情况,否则我只需要运行一次转换就可以使用自己喜欢的模式。这使它显得笨拙,看起来像:“当您只有一把锤子时,一切开始看起来像钉子。”
nfechner 2011年

这是一种更为实用的方法:) for (var oElement, i = 0; oElement = aMenuItemsElements; i++ { console.log(oElement); }
Daniel Sokolowski

这里的问题是您不能嵌套另一个for (var i…)循环,因为for循环不会创建自己的作用域(就像现在在C / C ++中那样)。然后i弄混了。
詹斯(Jens)

9

2020更新:nodeList.forEach()现在是官方标准,并且在所有当前浏览器中均受支持。

较旧的浏览器可以使用下面的polyfill。

要对JavaScript中的列表进行操作(例如使用forEach()),必须将NodeList转换为Array。

这不是真的。.forEach()在当前的浏览器中工作。如果缺少它,则可以将.forEach()从Array添加到NodeList,它可以正常工作:

if ( ! NodeList.prototype.forEach ) {
  NodeList.prototype.forEach = Array.prototype.forEach;
}

您现在可以运行:

myNodeList.forEach(function(node){...})

像数组一样遍历NodeList。

这比到处的.call()生成的代码更短,更简洁。


1
正是我所需要的答案,这3行节省了大量时间。所有其他答案都需要更改一堆代码,而我不明白为什么。
Scribblemacher


@DuBistKomisch这是一个polyfill,仅当标准NodeList.foreach()不存在时才应用。
mikemaccana

1
啊,我不好,没意识到他们实际上是forEach专门添加的,我是来这里找的filter
DuBistKomisch

@DuBistKomisch可以使用相同的技术filter,但是NodeList.prototype.dbkFilter如果您担心将来会使用其他实现标准,则可以使用一个非正式名称或类似名称。
mikemaccana

2

ES6允许使用一些很酷的方法,var nodeArray = Array.from(nodeList)但我最喜欢的方法是新的传播算子。

var nodeArray = Array(...nodeList);

完美的解决方案!该解决方案也适用于Typescript。
Nirus

我想补充一点,只要您不转译到ES5或更低版本,这仅适用于TypeScript。
鲁迪

2

在ES6中与我合作

假设您有这样的节点列表

<ul>
  <li data-time="5:17">Flexbox video</li>
  <li data-time="8:22">Flexbox video</li>
  <li data-time="3:24">Redux video</li>
  <li data-time="5:17">Flexbox video</li>
  <li data-time="7:17">Flexbox video</li>
  <li data-time="4:17">Flexbox video</li>
  <li data-time="2:17">Redux video</li>
  <li data-time="7:17">Flexbox video</li>
  <li data-time="9:54">Flexbox video</li>
  <li data-time="5:53">Flexbox video</li>
  <li data-time="7:32">Flexbox video</li>
  <li data-time="2:47">Redux video</li>
  <li data-time="9:17">Flexbox video</li>

</ul>


const items = Array.from(document.querySelectorAll('[data-time]'));

console.log(items);

2

我使用以下内容是因为我认为这是最容易阅读的内容:

const elements = document.getElementsByClassName('element');
[...elements].forEach((element) => {
   // code
});


1

好吧,这对我也适用:

const elements = Object.values( document.querySelector(your selector here) )

Object.values()返回Array给定对象的值。NodeList是对象,就像JS中的一切一样。

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/values

但是它与IE不兼容,所以我认为这Array.prototype.*array_method*.call(yourNodeList)是最好的选择。有了这个,你可以调用你的任何数组方法NodeList


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.