将HTMLCollection转换为数组的最有效方法

有更有效的方法来转换一个HTMLCollection到数组,而不是通过迭代的内容说集合和手动推每个项目到数组?

421673 次浏览
var arr = Array.prototype.slice.call( htmlCollection )

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

编辑

因为这得到了很多的观点,注意(根据@oriol的评论),下面更简洁的表达式是有效地等效的:

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

但是请注意@JussiR的评论,与“verbose”表单不同,它确实在进程中创建了一个空的、未使用的、实际上不可用的数组实例。编译器对此的处理超出了程序员的理解范围。

编辑

自ECMAScript 2015 (ES 6)以来,还有< em > Array.from < / em >:

var arr = Array.from(htmlCollection);

编辑

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

var arr = [...htmlCollection];

我已经确认,上述两个工作在NodeList

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

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

# EYZ0:

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可能是因为它不是在每个浏览器上都可用。恐怕性能是相当糟糕的,因为有一个回落是一个javascript循环在iterable

这是我个人的解决方案,基于这里的信息(这篇文章):

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

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

我看到了一种更简洁的方法来获取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
}

我知道这是一个老问题,但我觉得公认的答案有点不完整;所以我想先把这个扔出去。

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

let arry = [...htmlCollection]

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

let arry = Array.from(htmlCollection)

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

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

由于jsperf目前仍处于关闭状态,下面是一个比较不同方法性能的jsfiddle。# EYZ0

为了有效地将类数组转换为数组,我们可以使用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的对象,但缺少很多函数定义:

类数组对象看起来像数组。它们有不同的编号 元素和length属性。但相似之处仅此而已。 类数组对象不具有Array的任何函数,而for-in 循环甚至不起作用!< / p >

我认为在HTMLCollection的实例上使用HTMLCollection2比将集合转换为数组(例如,[...collection]Array.from(collection))要好得多,因为在后一种情况下,一个集合不必要地隐式迭代并创建了一个新的数组对象,这消耗了额外的资源。Array.prototype迭代函数可以安全地调用从[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>

有时候,即使你以正确的方式写了代码,但它仍然不能正常工作。

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

你得到空数组。 像,这< / p >

HTMLCollection []
[]

Console_javascript

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

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

如下所示, # EYZ0 < / p >

最终输出

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]