繁体   English   中英

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

[英]How can I test the equality of two NodeLists?

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

getNodeList('foo');

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

document.querySelectorAll('.foo');

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

这样做不起作用:

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

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

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

数组相等是通过引用来实现的,而不是通过内容来实现的。

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')), Array.from(document.querySelectorAll('.foo'))

到目前为止,您所拥有的似乎没问题,但效率低下(您可能会多次重新计算document.querySelectorAll(...)indexOf )。

还有一个错误:如果querySelectorAll返回的元素多于第一个节点列表,但它们在其他方面相等,则您的函数将返回true

您还可以进一步简化比较:

function nodeListsAreEqual( list1, list2 ) {
    if ( list1.length !== list2.length ) {
        return false;
    }
    return Array.from( list1 ).every( ( node, index ) => node === list2[ index ] );
}

如果您不介意安装第三方库,那么从 NPM 中获取deep-equal并执行以下操作:

deepEqual(Array.from(getNodeList('foo')), Array.from(document.querySelectorAll('.foo')))

这确保您的列表只计算一次,并将列表比较的所有血腥细节封装到一个单独的函数中。 您的代码应该简单地调用一个相等函数,而不是将您的应用程序关注点与列表结构的低级遍历混合在一起。 (但你可能已经知道了!)

如果您不喜欢Array.from的冗长,请使用Array.from

deepEqual([...getNodeList('foo')], [...document.querySelectorAll('.foo')])

如果效率很重要,您将需要进行一些分析。

我想出了这个似乎有效的方法,使用 ES6 特性:

const isEqual = [...getNodeList('foo')].every((node, index) => {
    return Array.from(document.querySelectorAll('.foo')).indexOf(node) === index
});

本质上,我们测试第一个 NodeList 中的每个项目是否存在于相同索引处的第二个 NodeList 中。 如果 NodeLists 之间存在任何差异,则应返回 false。

在需要比较可能不共享相同节点顺序的 NodeLists 之后,我重新审视了这个,但节点是相等的,并提出了这个:

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)
    });
}

一个更简单但可能更快的@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)
      }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM