在ES6中筛选或映射节点列表

Chr*_*phe 52 javascript arrays filter nodelist ecmascript-6

在ES6中过滤或映射节点列表的最有效方法是什么?

根据我的读数,我会使用以下选项之一:

[...nodelist].filter
Run Code Online (Sandbox Code Playgroud)

要么

Array.from(nodelist).filter
Run Code Online (Sandbox Code Playgroud)

你会推荐哪一个?有没有更好的方法,例如没有涉及数组?

log*_*yth 80

  • [...nodelist] 如果对象是可迭代的,将生成一个对象的数组.
  • Array.from(nodelist)如果对象是可迭代的,或者如果对象是类似数组(有.length和数字道具),将从对象中生成一个数组

如果NodeList.prototype[Symbol.iterator]存在,您的两个示例将是相同的,因为两个示例都涵盖了迭代.如果您的环境尚未配置NodeList为可迭代,则第一个示例将失败,第二个示例将成功.Babel目前无法正确处理此案例.

因此,如果您NodeList的可迭代性,那么您使用它真的取决于您.我可能会根据具体情况选择.一个好处Array.from是它需要映射函数的第二个参数,而第一个[...iterable].map(item => item)必须创建一个临时数组,Array.from(iterable, item => item)不会.但是,如果您没有映射列表,则无关紧要.

  • 请注意,IE 不支持“Array.from”。 (2认同)
  • @YannDìnendal 确实如此,但这个问题是在问 ES6,而 IE 根本不支持 ES6,所以已经是死胡同了。 (2认同)
  • 对,是真的。:) 我应该澄清我的意思:如果你依赖 Babel 将 es6 转译为 es5,默认情况下它不会填充原型方法。所以需要注意一些事情。:) (2认同)

gow*_*eon 14

我找到了一个直接在 NodeList 上使用的引用map

Array.prototype.map.call(nodelist, fn)
Run Code Online (Sandbox Code Playgroud)

我还没有测试过它,但它看起来可能会更快,因为它应该直接访问 NodeList。


Ser*_*kyy 12

TL; DR;

Array.prototype.slice.call(nodelist).filter
Run Code Online (Sandbox Code Playgroud)

slice()方法返回一个数组.返回的数组是一个浅的集合副本(NodeList) 所以它的工作速度比**Array.from()**快

原始集合的元素将复制到返回的数组中,如下所示:

  • 对于对象引用(而不是实际对象),slice将对象引用复制到新数组中.原始数组和新数组都引用相同的对象.如果引用的对象发生更改,则更改对新的和原始数组都可见.
  • 对于字符串,数字和布尔值(不是String,Number和Boolean对象),slice会将值复制到新数组中.对一个数组中的字符串,数字或布尔值的更改不会影响另一个数组.

关于论点的简短解释

Array.prototype.slice(beginIndex,endIndex)

  • 采用可选的args beginIndex和endIndex.如果未提供切片,则切片使用beginIndex == 0,因此它将从集合中提取所有项目

Array.prototype.slice.call(namespace,beginIndex,endIndex)

  • 将对象作为第一个参数.如果我们使用集合作为对象,它实际上意味着我们直接从该对象namespace.slice()调用slice方法

  • 感谢您提供此代码段,该代码段可能会提供一些有限的即时帮助.正确的解释将通过展示为什么这是一个很好的解决问题的方法来大大提高其长期价值,并使其对其他类似问题的未来读者更有用.请编辑您的答案以添加一些解释,包括您所做的假设. (2认同)

jav*_*web 7

[...a].filterArray.from(a).filter

性能上没有“真正”的差异,Array.from可能会快一点,因为您不是Array在“JS 级别”创建新的,但它直接发生在本机代码中。

性能 - 考虑使用其中任何一个

然而,为了性能(并避免“ Array-ing”),您应该考虑为什么要过滤 aNodeList以及您从哪里/如何获得它。id在许多情况下,您只需要通过或通过或其他 CSS 选择器来获取特定元素class

document.querySelectorAll速度快了10 倍 - 200 倍,适用于任何 CSS 选择器
document.getElementById甚至更快(但当然需要id

如果您提供预存储的父级来查看,您甚至可以优化querySelectorAll或绕过“未知”情况,让我给您举个例子:

let mainbar = document.getElementById('mainbar');
mainbar.querySelectorAll('.flex--item');
Run Code Online (Sandbox Code Playgroud)

几乎快 10 倍

Array.from(a).filter(el => el.classList.contains("flex--item"))
Run Code Online (Sandbox Code Playgroud)

另请注意,这document.querySelectorAll('#mainbar .flex--item');仍然比Array过滤快约 5 倍,但比使用id.

除了更好的性能之外,您还总是会得到NodeList(它可能是空的,但它仍然会是NodeList),这对于两者都document.querySelectorAll()适用Element.querySelectorAll()


pan*_*ter 5

这个怎么样:

// Be evil. Extend the prototype.
if (window.NodeList && !NodeList.prototype.filter) {
  NodeList.prototype.filter = Array.prototype.filter;
}

// Use it like you'd expect:
const noClasses = document
  .querySelectorAll('div')
  .filter(div => div.classList.length === 0)
Run Code Online (Sandbox Code Playgroud)

它与NodeList.forEach 的 MDN 文档(在“Polyfill”下)中提到的方法相同,它适用于 IE11、Edge、Chrome 和 FF。

  • 轻微警告,现在 nodeList.filter 将为您提供一个数组而不是节点列表。应该不是问题,但是很容易忘记^^ (4认同)