繁体   English   中英

将 JavaScript NodeList 转换为数组的最快方法?

[英]Fastest way to convert JavaScript NodeList to Array?

之前在这里回答的问题说这是最快的方法:

//nl is a NodeList
var arr = Array.prototype.slice.call(nl);

在我的浏览器上进行基准测试时,我发现它比这慢了 3 倍以上:

var arr = [];
for(var i = 0, n; n = nl[i]; ++i) arr.push(n);

他们都生产相同的 output,但我很难相信我的第二个版本是最快的方法,特别是因为人们在这里说了其他话。

这是我的浏览器(Chromium 6)中的一个怪癖吗? 还是有更快的方法?

编辑:对于任何关心的人,我选择了以下内容(这似乎是我测试的每个浏览器中最快的):

//nl is a NodeList
var l = []; // Will hold the array of Node's
for(var i = 0, ll = nl.length; i != ll; l.push(nl[i++]));

EDIT2:我找到了一种更快的方法

// nl is the nodelist
var arr = [];
for(var i = nl.length; i--; arr.unshift(nl[i]));

使用 ES6,我们现在有一种从 NodeList 创建数组的简单方法: Array.from()函数。

// nl is a NodeList
let myArray = Array.from(nl)

2021 年更新: nodeList.forEach() 现在是标准的,并且在所有当前浏览器中都受支持(桌面和移动设备上大约 95% )。

所以你可以简单地做:

document.querySelectorAll('img').forEach(highlight);

其他案例

如果您出于某种原因想要将其转换为数组,而不仅仅是迭代它 - 这是一个完全相关的用例 - 您可以使用[...destructuring]Array.from从 ES6

let array1 = [...mySetOfElements];
// or
let array2 = Array.from(mySetOfElements);

这也适用于不是 NodeLists 的其他类似数组的结构

  • 例如document.getElementsByTagName返回的HTMLCollection
  • 具有长度属性和索引元素的对象
  • 可迭代对象( MapSet等对象)



过时的 2010 年答案

在某些浏览器中,第二个往往更快,但重点是您必须使用它,因为第一个不是跨浏览器。 即使时代变了

@kangaxIE 9 预览版

Array.prototype.slice现在可以将某些宿主对象(例如 NodeList's)转换为数组——大多数现代浏览器已经能够做到这一点已经有一段时间了。

例子:

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

这是使用ES6 扩展运算符的一种新的很酷的方法:

let arr = [...nl];

在 ES6 中,您可以使用:

  • 数组.from

    let array = Array.from(nodelist)

  • 扩展运算符

    let array = [...nodelist]

一些优化:

  • 将 NodeList 的长度保存在变量中
  • 在设置之前明确设置新数组的长度。
  • 访问索引,而不是推送或取消移动。

代码( jsPerf ):

var arr = [];
for (var i = 0, ref = arr.length = nl.length; i < ref; i++) {
 arr[i] = nl[i];
}

最快和跨浏览器是

for(var i=-1,l=nl.length;++i!==l;arr[i]=nl[i]);

正如我比较

http://jsbin.com/oqeda/98/edit

*感谢@CMS 的想法!

铬(类似于谷歌浏览器)火狐歌剧

结果将完全取决于浏览器,为了给出客观的判断,我们必须进行一些性能测试,这里有一些结果,你可以在这里运行它们:

铬 6:

火狐 3.6:

火狐 4.0b2:

野生动物园 5:

IE9 平台预览版 3:

假设nodeList = document.querySelectorAll("div") ,这是将nodelist转换为数组的简洁形式。

var nodeArray = [].slice.call(nodeList);

看我在这里使用它。

NodeList.prototype.forEach = Array.prototype.forEach;

现在你可以做 document.querySelectorAll('div').forEach(function()...)

更快更短:

// nl is the nodelist
var a=[], l=nl.length>>>0;
for( ; l--; a[l]=nl[l] );

这是我在 JS 中使用的函数:

function toArray(nl) {
    for(var a=[], l=nl.length; l--; a[l]=nl[l]);
    return a;
}

在这里查看这篇博客文章,讨论同样的事情。 据我所知,额外的时间可能与沿着作用域链向上走有关。

以下是截至本文发布之日更新的图表(“未知平台”图表是 Internet Explorer 11.15.16299.0):

Safari 11.1.2火狐 61.0铬 68.0.3440.75Internet Explorer 11.15.16299.0

从这些结果来看,似乎 preallocate 1 方法是最安全的跨浏览器赌注。

这里有一个衬垫,我不确定它是否安全,但它对我有用,它用数组覆盖 nodelist 变量,因为我不再使用 nodelist,因为我将它转换为数组。 我发现这个解决方案更干净,因为它只使用一个变量。

this.openButtons = [...this.openButtons]

最简单的方法:

Array.from(document.querySelectorAll('.back-top'))

就去做吧 vat arr = [...nodeList]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM