簡體   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