在 ES6 中过滤或映射节点列表
Filter or map nodelists in ES6
在 ES6 中过滤或映射节点列表的最有效方法是什么?
根据我的阅读,我会使用以下选项之一:
[...nodelist].filter
或
Array.from(nodelist).filter
你会推荐哪一个?是否有更好的方法,例如不涉及数组?
如果对象是可迭代的,[...nodelist]
将创建一个对象数组。
Array.from(nodelist)
如果对象是可迭代的 或 如果对象是类数组(具有 .length
和数字道具)
如果 NodeList.prototype[Symbol.iterator]
存在,你的两个例子将是相同的,因为这两种情况都包含可迭代对象。如果您的环境尚未配置为 NodeList
是可迭代的,那么您的第一个示例将失败,而第二个将成功。 Babel
目前 does not handle this case properly。
因此,如果您的 NodeList
是可迭代的,那么使用哪种完全取决于您。我可能会根据具体情况进行选择。 Array.from
的一个好处是它接受映射函数的第二个参数,而第一个 [...iterable].map(item => item)
必须创建一个临时数组,而 Array.from(iterable, item => item)
则不需要。但是,如果您不映射列表,那没关系。
TL;DR;
Array.prototype.slice.call(nodelist).filter
slice() 方法 returns 一个数组。
返回的数组是集合 (NodeList) 的浅表副本
所以它比 Array.from() 工作得更快
所以它的工作速度和 Array.from()
一样快
原始集合的元素被复制到返回的数组中,如下所示:
- 对于对象引用(而不是实际对象),slice 将对象引用复制到新数组中。原始数组和新数组都引用同一个对象。如果引用的对象发生更改,则更改对新数组和原始数组都是可见的。
- 对于字符串、数字和布尔值(不是字符串、数字和布尔对象),slice 将值复制到新数组中。对一个数组中的字符串、数字或布尔值的更改不会影响另一个数组。
关于参数的简短说明
Array.prototype.slice(beginIndex, endIndex)
- 采用可选参数 beginIndex 和 endIndex。
如果没有提供,切片使用 beginIndex == 0,因此它从集合中提取所有项目
Array.prototype.slice.call(namespace, beginIndex, endIndex)
- 将一个对象作为第一个参数。如果我们将集合用作对象,它的字面意思是我们直接从该对象调用 slice 方法 namespace.slice()
我发现一个 reference 直接在 NodeList 上使用 map
Array.prototype.map.call(nodelist, fn)
我还没有测试过,但是这似乎会更快,因为它应该直接访问 NodeList。
这个怎么样:
// 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)
它与 the MDN docs for NodeList.forEach(在 'Polyfill' 下)中提到的方法相同,适用于 IE11、Edge、Chrome 和 FF .
在 ES6 中过滤或映射节点列表
我就是从这个简单的函数中走出来的。 @see https://developer.mozilla.org/fr/docs/Web/API/NodeList/entries#exemple
function filterNodeList(NodeList, callback) {
if (!typeof callback === "function") callback = (i) => i; // Any have better idear?
const Result = document.createElement("div");
//# No need to filter empty NodeList
if (Node.length === 0) return Node;
for (let i = 0; i < Node.length; i++) {
if (callback(Node.item(i))) Result.appendChild(Node.item(i));
}
return Result.childNodes;}
我愿意学习更多:>
[...a].filter
对比 Array.from(a).filter
不是“真正的”性能差异,Array.from
可能会快一点点,因为您没有在“JS 级别”上创建新的 Array
,但它发生了直接在本机代码中。
性能 - 考虑不使用或者
但是对于性能(并且为了避免“Array
-ing”)你应该考虑为什么你过滤NodeList
和 where/how 你明白了吗?在许多情况下,您只需要通过 id
或 class
或其他 CSS 选择器来选择特定元素。
document.querySelectorAll
就像 10 倍 - 200 倍快 并且适用于任何 CSS 选择器
document.getElementById
更快(但当然需要 id
)
你甚至可以优化 querySelectorAll
或绕过“not-yet-known”案例,如果你提供 pre-stored parent 来查看,让我举个例子:
let mainbar = document.getElementById('mainbar');
mainbar.querySelectorAll('.flex--item');
几乎比
快 10 倍
Array.from(a).filter(el => el.classList.contains("flex--item"))
另请注意,document.querySelectorAll('#mainbar .flex--item');
仍然比 Array
过滤快约 5 倍,但比 pre-storing 和 parent 的 id
慢约 2 倍.
除了更好的性能,你 也总是会得到 NodeList
(它可能是空的,但它仍然是 NodeList
) document.querySelectorAll()
and Element.querySelectorAll()
使用 ECMAS 2016:
let nodes = [...document.querySelector('__SELECTOR__').childNodes].filter(item => item.nodeType === 1);
在 ES6 中过滤或映射节点列表的最有效方法是什么?
根据我的阅读,我会使用以下选项之一:
[...nodelist].filter
或
Array.from(nodelist).filter
你会推荐哪一个?是否有更好的方法,例如不涉及数组?
-
如果对象是可迭代的,
[...nodelist]
将创建一个对象数组。Array.from(nodelist)
如果对象是可迭代的 或 如果对象是类数组(具有.length
和数字道具)
如果 NodeList.prototype[Symbol.iterator]
存在,你的两个例子将是相同的,因为这两种情况都包含可迭代对象。如果您的环境尚未配置为 NodeList
是可迭代的,那么您的第一个示例将失败,而第二个将成功。 Babel
目前 does not handle this case properly。
因此,如果您的 NodeList
是可迭代的,那么使用哪种完全取决于您。我可能会根据具体情况进行选择。 Array.from
的一个好处是它接受映射函数的第二个参数,而第一个 [...iterable].map(item => item)
必须创建一个临时数组,而 Array.from(iterable, item => item)
则不需要。但是,如果您不映射列表,那没关系。
TL;DR;
Array.prototype.slice.call(nodelist).filter
slice() 方法 returns 一个数组。
返回的数组是集合 (NodeList) 的浅表副本
所以它比 Array.from() 工作得更快
所以它的工作速度和 Array.from()
原始集合的元素被复制到返回的数组中,如下所示:
- 对于对象引用(而不是实际对象),slice 将对象引用复制到新数组中。原始数组和新数组都引用同一个对象。如果引用的对象发生更改,则更改对新数组和原始数组都是可见的。
- 对于字符串、数字和布尔值(不是字符串、数字和布尔对象),slice 将值复制到新数组中。对一个数组中的字符串、数字或布尔值的更改不会影响另一个数组。
关于参数的简短说明
Array.prototype.slice(beginIndex, endIndex)
- 采用可选参数 beginIndex 和 endIndex。 如果没有提供,切片使用 beginIndex == 0,因此它从集合中提取所有项目
Array.prototype.slice.call(namespace, beginIndex, endIndex)
- 将一个对象作为第一个参数。如果我们将集合用作对象,它的字面意思是我们直接从该对象调用 slice 方法 namespace.slice()
我发现一个 reference 直接在 NodeList 上使用 map
Array.prototype.map.call(nodelist, fn)
我还没有测试过,但是这似乎会更快,因为它应该直接访问 NodeList。
这个怎么样:
// 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)
它与 the MDN docs for NodeList.forEach(在 'Polyfill' 下)中提到的方法相同,适用于 IE11、Edge、Chrome 和 FF .
在 ES6 中过滤或映射节点列表
我就是从这个简单的函数中走出来的。 @see https://developer.mozilla.org/fr/docs/Web/API/NodeList/entries#exemple
function filterNodeList(NodeList, callback) {
if (!typeof callback === "function") callback = (i) => i; // Any have better idear?
const Result = document.createElement("div");
//# No need to filter empty NodeList
if (Node.length === 0) return Node;
for (let i = 0; i < Node.length; i++) {
if (callback(Node.item(i))) Result.appendChild(Node.item(i));
}
return Result.childNodes;}
我愿意学习更多:>
[...a].filter
对比 Array.from(a).filter
不是“真正的”性能差异,Array.from
可能会快一点点,因为您没有在“JS 级别”上创建新的 Array
,但它发生了直接在本机代码中。
性能 - 考虑不使用或者
但是对于性能(并且为了避免“Array
-ing”)你应该考虑为什么你过滤NodeList
和 where/how 你明白了吗?在许多情况下,您只需要通过 id
或 class
或其他 CSS 选择器来选择特定元素。
document.querySelectorAll
就像 10 倍 - 200 倍快 并且适用于任何 CSS 选择器
document.getElementById
更快(但当然需要 id
)
你甚至可以优化 querySelectorAll
或绕过“not-yet-known”案例,如果你提供 pre-stored parent 来查看,让我举个例子:
let mainbar = document.getElementById('mainbar');
mainbar.querySelectorAll('.flex--item');
几乎比
快 10 倍Array.from(a).filter(el => el.classList.contains("flex--item"))
另请注意,document.querySelectorAll('#mainbar .flex--item');
仍然比 Array
过滤快约 5 倍,但比 pre-storing 和 parent 的 id
慢约 2 倍.
除了更好的性能,你 也总是会得到 NodeList
(它可能是空的,但它仍然是 NodeList
) document.querySelectorAll()
and Element.querySelectorAll()
使用 ECMAS 2016:
let nodes = [...document.querySelector('__SELECTOR__').childNodes].filter(item => item.nodeType === 1);