1. ホーム
  2. javascript

NodeListはいつ生きていて、いつ静止しているのか?

2023-08-19 05:34:25

質問

に対する MDN から ノードリスト :

場合によっては、NodeList はライブコレクションであり、DOM の変更がコレクションに反映されることを意味します。 DOM の変更がコレクションに反映されることを意味します。例えば Node.childNodes はライブです。

 var parent = document.getElementById('parent');
 var child_nodes = parent.childNodes;
 console.log(child_nodes.length); // let's assume "2"
 parent.appendChild(document.createElement('div'));
 console.log(child_nodes.length); // should output "3"

他のケースでは NodeList は静的なコレクションであり、その後の DOM の変更がコレクションの内容に影響しないことを意味します。 DOM が変更されても、コレクションの内容には影響しません。 document.querySelectorAllは静的なNodeListを返します。

だから......ちょっと迷惑!?DOM API のさまざまな部分をすべて個別にチェックすることなく、どのメソッドがライブのリストを返し、どのメソッドがスタティックなリストを返すかについての中央リファレンスはあるのでしょうか? また ルール があるのでしょうか?

どのように解決するのですか?

各メソッドの情報には、ライブかどうかの詳細が書かれていますが、それを判断するための標準的な規約はないようです。

document.getElementsByClassName()HTMLCollection であり、ライブである。

document.getElementsByTagName()HTMLCollection であり、ライブである。

document.getElementsByName()NodeList であり、ライブである。

document.querySelectorAll()NodeList であり ではない を生きている。

HTMLCollection は常にライブであるように見える

<ブロッククオート

HTMLCollectionはノードのリストである。個々のノードは 序数か、ノードのnameかid属性でアクセスできます。

注意: HTML DOM のコレクションはライブであると仮定されます。 つまり、基礎となるドキュメントが変更されると、自動的に更新されます。 という意味です。

http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-75708506

つまり、HTMLコレクションは 常に であり、一方 nodeList はより一般的な構成で、DOM にあるかどうかわかりません。

NodeList オブジェクトはノードのコレクションです... NodeList インターフェースは、ノードの順序付きコレクションの抽象化を提供します。 ノードのコレクションを抽象化したもので、このコレクションがどのように実装されるかを定義したり制限したりすることはありません。 を定義または制限することなく、ノードの順序付きコレクションの抽象化を提供します。DOM の NodeList オブジェクトは生きています。

http://www.w3.org/TR/DOM-Level-3-Core/core.html#td-live

いい感じでしょう?

<ブロッククオート

コレクションは、DOMノードのリストを表すオブジェクトです。A コレクションはライブでもスタティックでも構いません。特に断りのない限り、コレクションは コレクションはライブでなければなりません。

http://www.w3.org/TR/2012/WD-dom-20120405/#collections

というわけで、静的コレクションは仕様でそのように示されることになります。つまり、このロジックで document.querySelectorAll() はコレクションですが、それは ではなく になっています。なぜなら、コレクションはライブであってもなくても良いのですが、コレクションは は生きていなければならないからです...。この区別は超便利ではありません。

さて、ここで、ある文字列が collection が生きているかどうかを判定する簡単な方法です。 DOM に追加し (セレクタにマッチするように)、長さが変更されたかどうかを確認し、削除します (したがってページには影響がありません)。

デモ

function isLive(collection) {
    if (HTMLCollection.prototype.isPrototypeOf(collection)) return true // HTMLCollections are always live

    const length = collection.length;
    if (!length) return undefined; // Inconclusive

    const el = collection.item(0);
    const parent = el.parentNode;
    const clone = el.cloneNode();

    clone.style.setProperty('display', 'none', 'important');
    parent.appendChild(clone);

    const live = collection.length !== length;
    parent.removeChild(clone);
    return live;
}

const divs1 = document.getElementsByClassName('c');
const divs2 = document.getElementsByTagName('span');
const divs3 = document.getElementsByName('notFound');
const divs4 = document.querySelectorAll('.c');

console.log("document.getElementsByClassName('c'):", divs1.toString()); //   [object HTMLCollection]
console.log("document.getElementsByTagName('notFound'):", divs2.toString()); //  [object HTMLCollection]
console.log("document.getElementsByName('notFound'):", divs3.toString()); // [object NodeList]
console.log("document.querySelectorAll('.c'):", divs4.toString()); //        [object NodeList]

console.log('isLive(divs1)', isLive(divs1)); // true
console.log('isLive(divs2)', isLive(divs2)); // true
console.log('isLive(divs3)', isLive(divs3)); // undefined
console.log('isLive(divs4)', isLive(divs4)); // false
<html>
    <body>
        <div>
            <div class="c">C1</div>
            <div class="c">C2</div>
        </div>
        <div>
            <div class="c">C3</div>
            <div class="c">C4</div>
        </div>
    </body>
</html>