假设我有一个自定义函数,我希望它会返回一个NodeList:
getNodeList('foo');
我希望此NodeList与从以下位置返回的NodeList相同:
document.querySelectorAll('.foo');
如何检查我的期望是正确的?
这样做不起作用:
getNodeList('foo') == document.querySelectorAll('.foo')
我敢肯定有一个很好的技术原因为什么它不起作用,因为document.querySelectorAll('.foo') == document.querySelectorAll('.foo')
也不起作用,我认为这是可以预期的。
如何测试两个NodeList是否包含相同的HTML节点?
答案 0 :(得分:4)
数组引用是通过引用而不是内容来实现的。
let a = [1, 2, 3], b = [1, 2, 3]
let c = a
a == c // => true, since both refer to `a`
a == b // => false
如果要比较两个类似数组的对象,则必须按索引进行比较。
function eq(A, B) {
if (A.length !== B.length) return false;
for (let i = 0; i < A.length; i++) {
if (A[i] !== B[i]) return false;
}
return true;
}
当然,您总是可以使用一些函数式编程魔术:
let arrayEq = (A, B) => A.length === B.length && A.every((e, i) => e === B[i]);
但是只有在A是一个数组(不是NodeList)时,它才起作用。
然后尝试
eq(getNodeList('foo'), document.querySelectorAll('.foo'))
或
arrayEq(Array.from(getNodeList('foo'), document.querySelectorAll('.foo'))
答案 1 :(得分:2)
到目前为止,您所拥有的似乎还可以,但是效率很低(您可能会多次重新计算True
和document.querySelectorAll(...)
)。
还有一个错误:如果indexOf
返回的元素多于第一个节点列表,但它们相等,则您的函数将返回querySelectorAll
。
您还可以进一步简化比较:
true
答案 2 :(得分:2)
如果您不介意安装第三方库,请从NPM中抓取deep-equal
并执行以下操作:
deepEqual(Array.from(getNodeList('foo')), Array.from(document.querySelectorAll('.foo')))
这可确保您的列表仅计算一次,并将列表比较的所有详细信息封装到一个单独的函数中。您的代码应该只调用一个相等函数,而不要将您的应用程序问题与列表结构的底层遍历混合在一起。 (但是您可能已经知道了!)
如果您不喜欢Array.from
的冗长内容,请使用splats:
deepEqual([...getNodeList('foo')], [...document.querySelectorAll('.foo')])
如果效率很重要,则需要进行一些分析。
答案 3 :(得分:1)
我想出了这种方法,该方法似乎可以使用ES6功能:
const isEqual = [...getNodeList('foo')].every((node, index) => {
return Array.from(document.querySelectorAll('.foo')).indexOf(node) === index
});
实质上,我们测试第一个NodeList中的每个项目是否在第二个NodeList中以相同的索引存在。如果NodeList之间存在差异,则应返回false。
答案 4 :(得分:0)
在需要比较可能不共享相同顺序节点的NodeList之后,我重新进行了讨论,否则节点是相等的,并得出以下结论:
export default function nodeListsAreEqual(actual, expected) {
if ((actual.length || Object.keys(actual).length) !== (expected.length || Object.keys(expected).length)) {
return false;
}
return Array.from(actual).every(actualNode => {
return Array.from(expected).some(expectedNode => actualNode === expectedNode)
});
}
答案 5 :(得分:0)
一个更简单但可能更快的@mauroc8 版本:
const nodeEq = (A, B) => {
A = Array.from(A)
B = Array.from(B)
if (A.length !== B.length) return false
return A.every((a, b) => a.innerHTML === B[b].innerHTML)
}