NodeList 何时处于活动状态,何时为静态



来自 MDN for NodeList:

在某些情况下,NodeList 是一个实时集合,这意味着 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 不会影响集合的内容。 document.querySelectorAll 返回一个静态 NodeList。

所以。。。。有点烦人!对于哪些方法返回实时列表以及哪些方法返回静态列表,而无需单独检查 DOM API 的所有不同部分,是否有任何中心参考?这里有任何规则吗?

有关每个方法的信息详细说明了它是否有效,但似乎没有确定它的标准约定。

document.getElementsByClassName()HTMLCollection,而且是活的。

document.getElementsByTagName()HTMLCollection,而且是活的。

document.getElementsByName()NodeList,是现场直播。

document.querySelectorAll()NodeList不是活的。

HTMLCollection似乎永远是活的

HTMLCollection是节点的列表。单个节点可能是通过序号索引或节点的名称或 ID 属性访问。

注意:HTML DOM 中的集合被假定为实时的,这意味着当基础文档改变。

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

因此,HTML 集合始终"在 dom 中",而 nodeList 是一个更通用的结构,可能在 DOM 中,也可能不在 DOM 中。

节点列表对象是节点的集合...NodeList 接口提供有序的抽象节点的集合,而不定义或约束如何实现收集。DOM 中的 NodeList 对象是实时的。

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

听起来不错,对吧?

集合是表示 DOM 节点列表的对象。一个集合可以是实时的,也可以是静态的。除非另有说明,否则收集必须是实时的。

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

因此,静态集合将在规范中指示。因此,按照此逻辑,document.querySelectorAll()是一个集合,但它不在 DOM 中。因为虽然集合可能是实时的,也可能不是实时的,但 DOM 中的集合必须是实时的......这种区别并不是很有帮助。

好吧,这里有一个快速的方法来确定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>

我不知道

是否有中心引用,但这些是我知道的返回 HTMLCollection s 并活NodeList s 的方法和属性:

方法

  • parentNode.getElementsByClassName() - 返回HTMLCollection
  • parentNode.getElementsByTagName()   - 返回HTMLCollection
  • parentNode.getElementsByTagNameNS() - 返回HTMLCollection
  •   document.getElementsByName()      - 返回NodeList

性能

  • parentNode.children   - 返回一个HTMLCollection
  •       Node.childNodes - 返回NodeList

最新更新