【问题标题】:In JavaScript, what is the best way to convert a NodeList to an array?在 JavaScript 中,将 NodeList 转换为数组的最佳方法是什么?
【发布时间】:2011-11-19 13:21:38
【问题描述】:

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

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

NodeList 转换为Array 的最佳方法是什么?

【问题讨论】:

  • 我认为querySelectorAll()的返回值在技术上叫做NodeList。
  • 来自mdm "elementList = document.querySelectorAll(selectors);"
  • elementList 是变量名。同一页面描述了返回值的类型如何是 NodeList。
  • 感谢您的更正 - 已解决问题

标签: javascript arrays dom


【解决方案1】:

使用 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,你是对的!我的目标是es2015。谢谢!
  • @callback ES6 和 ES2015 是一回事
  • 请注意您无需将 nodeList 转换为数组即可使用 forEach() - 请参阅下面的答案。
【解决方案2】:

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

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

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

使用ES6 shim 也可以在旧版浏览器中使用。


如果您使用的是转译器(例如 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 提供了一个迭代器?
  • @ccyoung 但迭代器在不兼容的 ES6 浏览器中不起作用,因为您无法填充 Symbol 对象,因此最好使用 Array.from(myNodeList),因为它可以填充。
  • 所以我有这个问题,其中 Array.from(el.childNodes) 不返回第一个节点作为数组的一部分。
【解决方案3】:

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

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

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

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);
});

目前仅在最前沿的浏览器中提供,但如果您是 using a polyfill service,您将可以全面访问此功能。


如果您使用的是an ES6 transpiler,您甚至可以使用for..of 循环来代替:

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

【讨论】:

  • 谢谢。在较新的javascript思想/希望有更简洁的强制。
  • @cc young - 请注意,我使用 Array.prototype.forEach 而不是 [].forEach 的原因是因为后者创建了一个新的 Array 对象,这完全没有必要。
  • @JosephSilber 啊谢谢 - 那是创建的新数组是空的[]?我的想法是它会被垃圾收集并且内存影响可以忽略不计,有人可以对此发表评论吗?
  • @Daniel 这是真的,但仍然存在创建和销毁数组的计算。
【解决方案4】:

为什么要转换? - 只是 call Array 的函数直接在元素集合上;)

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

当然,假设 $querySelectorAll 的别名


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

【讨论】:

  • 假设$querySelectorAll
  • 您的回答暗示了 jQuery 的使用。如果是这样的话,这个愚蠢的行为是完全没有必要的,感谢.each()
  • 大声笑,为什么?没有什么能阻止你使用像 function $ ( s ) { return document.querySelectorAll(s); } 这样的别名。
  • 如果你要使用jQuery,那么更简洁的解决方案是:$('a').each(function(i, v) {...});
  • offtopic:EcmaScript 5 已经是一年的标准,所有当前一代的浏览器都支持新的数组方法,问题特别是关于在 NodeList aka Element 集合上使用这些方法。
【解决方案5】:

2020 年更新:nodeList.forEach() is now an official standard 并在所有当前浏览器中均受支持。

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

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

那不是真的。 .forEach() 适用于当前浏览器。如果它丢失了,您可以使用 polyfill 将 Array 中的 .forEach() 添加到 NodeList 并且效果很好:

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

你现在可以运行了:

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

像数组一样迭代 NodeList。

这会产生比任何地方的 .call() 更短、更简洁的代码。

【讨论】:

  • 这个答案正是我所需要的,这 3 行节省了很多时间。所有其他答案都需要更改一堆代码,我不明白为什么。
  • 投反对票可能是因为猴子修补内置原型被认为是不好的做法
  • @DuBistKomisch 这是一个 polyfill,仅在标准 NodeList.foreach() 不存在时应用。
  • 啊我的错,没有意识到他们实际上添加了forEach,我来这里是为了寻找filter
  • @DuBistKomisch 您可以对filter 使用相同的技术,但如果您担心未来的标准使用不同的实现,您可能希望给它一个非官方名称NodeList.prototype.dbkFilter 或类似名称。
【解决方案6】:

必须是forEach吗?您可以简单地使用 for 循环来遍历列表:

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

【讨论】:

  • +1 用于不添加不必要的数组转换的简单解决方案。仅供参考,您可以使用elementList[i],而不是elementList.item(i)
  • 就我个人而言,我发现forEach() 的编程风格更好,而且更简洁——ymmv
  • @cc young:其实我同意你的看法。除了在这种情况下,我需要运行转换才能使用我最喜欢的模式。这使它显得笨重,看起来像:“当你只有一把锤子时,一切都开始像钉子了。”
  • 这是一个更疯狂的方法:) for (var oElement, i = 0; oElement = aMenuItemsElements; i++ { console.log(oElement); }
  • 这里的问题是你不能嵌套另一个 for (var i…) 循环,因为 for 循环不会创建自己的范围(就像现在在 C/C++ 中那样)。然后i 搞混了。
【解决方案7】:

嗯,这对我也有用:

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

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

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values

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

【讨论】:

    【解决方案8】:

    ES6 允许像var nodeArray = Array.from(nodeList) 这样很酷的方式,但我最喜欢的是新的传播运算符。

    var nodeArray = Array(...nodeList);
    

    【讨论】:

    • 完美解决方案!此解决方案也适用于 Typescript。
    • 我想补充一点,只要您不转译到 ES5 或更低版本,这仅适用于 TypeScript。
    【解决方案9】:

    这在 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);
    

    【讨论】:

      【解决方案10】:

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

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

      【讨论】:

        【解决方案11】:

        TypeScript 版本:

        const allDayElements: Element[] = [].slice.call(document.querySelectorAll('span'));
        

        【讨论】:

          【解决方案12】:

          假设 elems 是一个 nodeList:

          var elems = document.querySelectorAll('select option:checked');
          

          那么就可以变成如下的数组了:

          var values = [].map.call(elems, function(obj) {
            return obj.value;
          });
          

          参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Example:_using_map_generically_querySelectorAll

          【讨论】:

            猜你喜欢
            • 2017-06-09
            • 2010-09-12
            • 2023-03-23
            • 2010-09-07
            • 2011-08-11
            • 1970-01-01
            • 2023-03-26
            相关资源
            最近更新 更多