在 ES6 中过滤或映射节点列表最有效的方法是什么?
根据我的阅读,我会使用以下选项之一:
[...nodelist].filter
或
Array.from(nodelist).filter
您会推荐哪一款?有没有更好的方法,例如不涉及数组?
[...nodelist]
将从对象中创建一个数组。Array.from(nodelist)
将从对象中创建一个数组或者如果对象是类似数组的(具有.length
和数字属性)NodeList.prototype[Symbol.iterator]
存在,那么您的两个示例将是相同的,因为这两种情况都涵盖了可迭代对象。但是,如果您的环境尚未配置为可迭代,则您的第一个示例将失败,而第二个示例将成功。
NodeList
目前无法妥善处理此案
。因此,如果您的
Babel
是可迭代的,那么这实际上取决于您使用哪个。我可能会根据具体情况进行选择。 NodeList
的一个好处是它需要映射函数的第二个参数,而第一个
Array.from
必须创建一个临时数组,而
[...iterable].map(item => item)
则不需要。但是,如果您没有映射列表,也没关系。我发现了一个
Array.from(iterable, item => item)
by
map
我还没有测试过它,但似乎这会更快,因为它应该直接访问 NodeList。TL;博士;
Array.prototype.map.call(nodelist, fn)
slice() 方法返回一个数组。 返回的数组是集合(NodeList)的浅表副本
所以它比Array.from()
运行得更快
所以它的工作速度和 Array.from() 一样快
原始集合的元素被复制到返回的数组中,如下所示:
对于对象引用(而不是实际对象),切片会将对象引用复制到新数组中。原始数组和新数组都引用同一个对象。如果引用的对象发生更改,则新数组和原始数组都可以看到这些更改。
Array.prototype.slice(beginIndex, endIndex)
采用可选参数 beginIndex 和 endIndex。 如果未提供切片,则使用 beginIndex == 0,因此它会从集合中提取所有项目
将一个对象作为第一个参数。如果我们使用集合作为对象,它的字面意思是我们直接从该对象调用 slice 方法
namespace.slice()[...a].filter
性能上没有“真正”的差异,
Array.from(a).filter
Array.from
,但它直接发生在本机代码中。
性能 - 考虑不使用
Array
-ing”),您应该考虑为什么
要过滤
Array
以及在哪里/如何获得它。在许多情况下,您只需要通过
NodeList
或 id
或其他 CSS 选择器来获得特定元素。
class
就像 10 倍 - 200 倍快
并且适用于任何 CSS 选择器
document.querySelectorAll
甚至更快(但当然需要document.getElementById
)
如果您提供预先存储的父级来查看,您甚至可以优化
id
或绕过“未知”情况,让我给您举个例子:
querySelectorAll
几乎比
快 10 倍
let mainbar = document.getElementById('mainbar');
mainbar.querySelectorAll('.flex--item');
Array.from(a).filter(el => el.classList.contains("flex--item"))
仍比 document.querySelectorAll('#mainbar .flex--item');
过滤快约 5 倍,但比使用
Array
预存储父级慢约 2 倍。
除了更好的性能之外,您还将始终获得
id
NodeList
),这对于NodeList
和document.querySelectorAll()
都适用
https://developer.mozilla.org/en-US/docs/Web/API/NodeList/entries#example
使用ECMAS 2016: