如何测试两个NodeList的相等性?

时间:2018-08-22 01:36:42

标签: javascript object nodelist

假设我有一个自定义函数,我希望它会返回一个NodeList:

getNodeList('foo');

我希望此NodeList与从以下位置返回的NodeList相同:

document.querySelectorAll('.foo');

如何检查我的期望是正确的?

这样做不起作用:

getNodeList('foo') == document.querySelectorAll('.foo')

我敢肯定有一个很好的技术原因为什么它不起作用,因为document.querySelectorAll('.foo') == document.querySelectorAll('.foo')也不起作用,我认为这是可以预期的。

如何测试两个NodeList是否包含相同的HTML节点?

6 个答案:

答案 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)

到目前为止,您所拥有的似乎还可以,但是效率很低(您可能会多次重新计算Truedocument.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)
      }