简体   繁体   English

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

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

Previously answered questions here said that this was the fastest way:之前在这里回答的问题说这是最快的方法:

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

In benchmarking on my browser I have found that it is more than 3 times slower than this:在我的浏览器上进行基准测试时,我发现它比这慢了 3 倍以上:

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

They both produce the same output, but I find it hard to believe that my second version is the fastest possible way, especially since people have said otherwise here.他们都生产相同的 output,但我很难相信我的第二个版本是最快的方法,特别是因为人们在这里说了其他话。

Is this a quirk in my browser (Chromium 6)?这是我的浏览器(Chromium 6)中的一个怪癖吗? Or is there a faster way?还是有更快的方法?

EDIT: For anyone who cares, I settled on the following (which seems to be the fastest in every browser that I tested):编辑:对于任何关心的人,我选择了以下内容(这似乎是我测试的每个浏览器中最快的):

//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: I found an even faster way EDIT2:我找到了一种更快的方法

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

With ES6, we now have a simple way to create an Array from a NodeList: the Array.from() function.使用 ES6,我们现在有一种从 NodeList 创建数组的简单方法: Array.from()函数。

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

2021 update: nodeList.forEach() is now standard and supported in all current browsers ( around 95% on both desktop & mobile ). 2021 年更新: nodeList.forEach() 现在是标准的,并且在所有当前浏览器中都受支持(桌面和移动设备上大约 95% )。

So you can simply do:所以你可以简单地做:

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

Other cases其他案例

If you for some reason want to convert it to an array, not just iterate over it - which is a completely relevant use-case - you can use [...destructuring] or Array.from since ES6如果您出于某种原因想要将其转换为数组,而不仅仅是迭代它 - 这是一个完全相关的用例 - 您可以使用[...destructuring]Array.from从 ES6

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

This also works for other array-like structures that aren't NodeLists这也适用于不是 NodeLists 的其他类似数组的结构

  • HTMLCollection returned by eg document.getElementsByTagName例如document.getElementsByTagName返回的HTMLCollection
  • objects with a length property and indexed elements具有长度属性和索引元素的对象
  • iterable objects (objects such as Map and Set )可迭代对象( MapSet等对象)



Outdated 2010 Answer过时的 2010 年答案

The second one tends to be faster in some browsers, but the main point is that you have to use it because the first one is just not cross-browser.在某些浏览器中,第二个往往更快,但重点是您必须使用它,因为第一个不是跨浏览器。 Even though The Times They Are a-Changin'即使时代变了

@kangax ( IE 9 preview ) @kangaxIE 9 预览版

Array.prototype.slice can now convert certain host objects (eg NodeList's) to arrays — something that majority of modern browsers have been able to do for quite a while. Array.prototype.slice现在可以将某些宿主对象(例如 NodeList's)转换为数组——大多数现代浏览器已经能够做到这一点已经有一段时间了。

Example:例子:

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

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

let arr = [...nl];

In ES6 you can either use:在 ES6 中,您可以使用:

  • Array.from数组.from

    let array = Array.from(nodelist)

  • Spread operator扩展运算符

    let array = [...nodelist]

Some optimizations:一些优化:

  • save the NodeList's length in a variable将 NodeList 的长度保存在变量中
  • explicitly set the new array's length before setting.在设置之前明确设置新数组的长度。
  • access the indices, rather than pushing or unshifting.访问索引,而不是推送或取消移动。

Code ( jsPerf ):代码( jsPerf ):

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

The most fast and cross browser is最快和跨浏览器是

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

As I compared in正如我比较

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

*Thanks @CMS for the idea! *感谢@CMS 的想法!

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

The results will completely depend on the browser, to give an objective verdict, we have to make some performance tests, here are some results, you can run them here :结果将完全取决于浏览器,为了给出客观的判断,我们必须进行一些性能测试,这里有一些结果,你可以在这里运行它们:

Chrome 6:铬 6:

Firefox 3.6:火狐 3.6:

Firefox 4.0b2:火狐 4.0b2:

Safari 5:野生动物园 5:

IE9 Platform Preview 3: IE9 平台预览版 3:

Assuming nodeList = document.querySelectorAll("div") , this is a concise form of converting nodelist to array.假设nodeList = document.querySelectorAll("div") ,这是将nodelist转换为数组的简洁形式。

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

See me use it here .看我在这里使用它。

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

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

faster and shorter :更快更短:

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

This is the function I use in my JS:这是我在 JS 中使用的函数:

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

Check out this blog post here that talks about the same thing. 在这里查看这篇博客文章,讨论同样的事情。 From what I gather, the extra time might have to do with walking up the scope chain.据我所知,额外的时间可能与沿着作用域链向上走有关。

Here are charts updated as of the date of this posting ("unknown platform" chart is Internet Explorer 11.15.16299.0):以下是截至本文发布之日更新的图表(“未知平台”图表是 Internet Explorer 11.15.16299.0):

Safari 11.1.2火狐 61.0铬 68.0.3440.75Internet Explorer 11.15.16299.0

From these results, it seems that the preallocate 1 method is the safest cross-browser bet.从这些结果来看,似乎 preallocate 1 方法是最安全的跨浏览器赌注。

One liner here, I am not sure if it is safe, but it works for me, it is overwriting the nodelist variable with an array, because I no longer use the nodelist, as I converted it to an array.这里有一个衬垫,我不确定它是否安全,但它对我有用,它用数组覆盖 nodelist 变量,因为我不再使用 nodelist,因为我将它转换为数组。 I find this solution cleaner as it uses just the one variable.我发现这个解决方案更干净,因为它只使用一个变量。

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