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

IT技术 javascript arrays nodelist
2021-01-27 22:03:54

以前在这里回答的问题说这是最快的方式:

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

它们都产生相同的输出,但我发现很难相信我的第二个版本是最快的方式,尤其是因为人们在这里另有说法。

这是我的浏览器(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]));
6个回答

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

// nl is a NodeList
let myArray = Array.from(nl)
这种新的 ES6 方法在速度上与上面提到的其他方法相比如何?
2021-03-11 22:03:54
Array.from 的好处是你可以使用 map 参数: console.log(Array.from([1, 2, 3], x => x + x)); // expected output: Array [2, 4, 6]
2021-03-23 22:03:54
@ user5508297 比切片调用技巧更好。比 for 循环慢,但这并不完全是我们可能想要一个不遍历它的数组。而且语法优美,简单易记!
2021-04-05 22:03:54

2021 年更新:nodeList.forEach() 现在是所有当前浏览器的标准和支持(在 dekstop 和 mobile 上约为 95%)。

所以你可以简单地做:

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

其他情况

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

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

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

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



过时的 2010 年答案

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

@kangax IE 9 预览版

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

例子:

Array.prototype.slice.call(document.childNodes);
这可以缩短为[].slice.call(document.childNodes):) ohhh 快乐的日子
2021-03-18 22:03:54
Array.prototype.slice 不跨浏览器,如果你考虑 IE8。
2021-03-26 22:03:54
因为 NodeLists 不是语言的一部分,它们是 DOM API 的一部分,众所周知,该 API 存在缺陷/不可预测,尤其是在 IE 中
2021-03-27 22:03:54
但它们不能在 IE 中的 NodeLists 上使用(我知道这很糟糕,但嘿,看看我的更新)
2021-04-05 22:03:54
是的,这就是我的回答基本上是关于 :) 虽然它在 2010 年比今天(2015 年)更相关。
2021-04-08 22:03:54

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

let arr = [...nl];
在typescript中对我不起作用。 ERROR TypeError: el.querySelectorAll(...).slice is not a function
2021-03-18 22:03:54
使用 Chrome 71,在 3 种 unshift 方法之后排在第三快:jsperf.com/nodelist-to-array/90
2021-03-31 22:03:54

在 ES6 中,您可以使用:

  • 数组.from

    let array = Array.from(nodelist)

  • 展开运算符

    let array = [...nodelist]

不添加任何新的东西已经写在以前的答案中。
2021-03-20 22:03:54

一些优化:

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

代码(jsPerf):

var arr = [];
for (var i = 0, ref = arr.length = nl.length; i < ref; i++) {
 arr[i] = nl[i];
}
可以剃一个通过使用阵列(长度),而不是创建阵列,然后分别浆纱它更多的时间。如果然后使用 const 声明数组及其长度,并在循环内使用 let,则最终比上述方法快 1.5%: const a = Array(nl.length), c = a.length; for (let b = 0; b < c; b++) { a[b] = nl[b]; 参见jsperf.com/nodelist-to-array/93
2021-03-25 22:03:54