544

除了遍历所述集合的内容并手动将每个项目推入数组之外,是否有更有效的方法将 HTMLCollection 转换为数组?

4

9 回答 9

940
var arr = Array.prototype.slice.call( htmlCollection )

使用“本机”代码将具有相同的效果。

编辑

由于这得到了很多意见,请注意(根据@oriol 的评论)以下更简洁的表达式实际上是等效的:

var arr = [].slice.call(htmlCollection);

但请注意,根据@JussiR 的评论,与“详细”形式不同,它确实在该过程中创建了一个空的、未使用的且确实不可用的数组实例。编译器对此做了什么超出了程序员的理解范围。

编辑

从 ECMAScript 2015 (ES 6) 开始,还有Array.from

var arr = Array.from(htmlCollection);

编辑

ECMAScript 2015 还提供了扩展运算符,它在功能上等同于Array.from(尽管注意Array.from支持映射函数作为第二个参数)。

var arr = [...htmlCollection];

我已经确认上述两种方法都适用于NodeList.

上述方法的性能比较:http: //jsben.ch/h2IFA

于 2008-10-21T18:06:47.567 回答
118

不确定这是否是最有效的,但简洁的 ES6 语法可能是:

let arry = [...htmlCollection] 

编辑:另一个,来自 Chris_F 评论:

let arry = Array.from(htmlCollection)
于 2016-05-05T04:23:12.927 回答
24

我看到了一种更简洁的方法来获取Array.prototype一般的方法,它也同样有效。将HTMLCollection对象转换为Array对象如下所示:

[].slice.call(yourHTMLCollectionObject);

而且,正如评论中提到的,对于 IE7 及更早版本的旧浏览器,您只需使用兼容性功能,例如:

function toArray(x) {
    for(var i = 0, a = []; i < x.length; i++)
        a.push(x[i]);

    return a
}

我知道这是一个老问题,但我觉得接受的答案有点不完整;所以我想我会把它扔在那里 FWIW。

于 2014-03-27T00:42:57.727 回答
7

对于跨浏览器实现,我建议您查看prototype.js $A函数

从 1.6.1 复制

function $A(iterable) {
  if (!iterable) return [];
  if ('toArray' in Object(iterable)) return iterable.toArray();
  var length = iterable.length || 0, results = new Array(length);
  while (length--) results[length] = iterable[length];
  return results;
}

它不使用Array.prototype.slice可能是因为它并非在每个浏览器上都可用。恐怕性能很差,因为回退是iterable.

于 2009-12-09T08:14:13.550 回答
6

这适用于所有浏览器,包括早期的 IE 版本。

var arr = [];
[].push.apply(arr, htmlCollection);

由于 jsperf 目前还处于 down 状态,这里有一个 jsfiddle 比较不同方法的性能。https://jsfiddle.net/qw9qf48j/

于 2016-08-13T06:35:55.327 回答
5

为了以有效的方式将类数组转换为数组,我们可以使用jQuery makeArray

makeArray:将类数组对象转换为真正的 JavaScript 数组。

用法:

var domArray = jQuery.makeArray(htmlCollection);

一点额外的:

如果您不想保留对数组对象的引用(大多数时候 HTMLCollections 是动态更改的,因此最好将它们复制到另一个数组中,此示例密切关注性能:

var domDataLength = domData.length //Better performance, no need to calculate every iteration the domArray length
var resultArray = new Array(domDataLength) // Since we know the length its improves the performance to declare the result array from the beginning.

for (var i = 0 ; i < domDataLength ; i++) {
    resultArray[i] = domArray[i]; //Since we already declared the resultArray we can not make use of the more expensive push method.
}

什么是类数组?

HTMLCollection是一个"array-like"对象,类数组对象类似于数组的对象,但缺少很多功能定义:

类数组对象看起来像数组。它们有各种编号的元素和一个长度属性。但这就是相似之处停止的地方。类数组对象没有 Array 的任何功能,for-in 循环甚至不起作用!

于 2018-07-10T18:40:55.380 回答
3

这是我个人的解决方案,基于此处的信息(此线程):

var Divs = new Array();    
var Elemns = document.getElementsByClassName("divisao");
    try {
        Divs = Elemns.prototype.slice.call(Elemns);
    } catch(e) {
        Divs = $A(Elemns);
    }

Gareth Davis 在他的帖子中描述了 $A:

function $A(iterable) {
  if (!iterable) return [];
  if ('toArray' in Object(iterable)) return iterable.toArray();
  var length = iterable.length || 0, results = new Array(length);
  while (length--) results[length] = iterable[length];
  return results;
}

如果浏览器支持最好的方式,ok,否则将使用跨浏览器。

于 2013-05-16T19:35:08.213 回答
2

有时,即使您以正确的方式编写代码,但仍然无法正常工作。

var allbuttons = document.getElementsByTagName("button");
console.log(allbuttons);

var copyAllButtons = [];
for (let i = 0; i < allbuttons.length; i++) {
  copyAllButtons.push(allbuttons[i]);
}
console.log(copyAllButtons);

你得到空数组。像这样

HTMLCollection []
[]

控制台_javascript

为了解决这个问题,您必须在 html 文件中的 body 标记之后添加 javascript 文件的链接。

<script src="./script.js"></script>

如下所示, html_file

最终输出

HTMLCollection(6) [button.btn.btn-dark.click-me, button.btn.btn-dark.reset, button#b, button#b, button#b, button#b, b: button#b]
(6) [button.btn.btn-dark.click-me, button.btn.btn-dark.reset, button#b, button#b, button#b, button#b]
于 2022-01-04T09:55:02.673 回答
1

我认为在 的实例上调用Array.prototype函数HTMLCollection是比将集合转换为数组(例如,[...collection]Array.from(collection))更好的选择,因为在后一种情况下,集合被不必要地隐式迭代并创建了一个新的数组对象,这会占用额外的资源。Array.prototype迭代函数可以安全地调用具有从 from 开始的连续数字键[0]和具有length此类键数量的有效数字值的属性的对象(包括,例如 和 的实例HTMLCollectionFileList,因此这是一种可靠的方法。另外,如果经常需要这样的操作,[]可以使用一个空数组来快速访问Array.prototype函数;或快捷方式Array.prototype可以改为创建。一个可运行的例子:

const _ = Array.prototype;
const collection = document.getElementById('ol').children;
alert(_.reduce.call(collection, (acc, { textContent }, i) => {
  return acc += `${i+1}) ${textContent}` + '\n';
}, ''));
<ol id="ol">
    <li>foo</li>
    <li>bar</li>
    <li>bat</li>
    <li>baz</li>
</ol>

于 2021-02-01T12:07:58.560 回答