【问题标题】:Difference between HTMLCollection, NodeLists, and arrays of objectsHTMLCollection、NodeLists 和对象数组之间的区别
【发布时间】:2023-03-23 14:20:01
【问题描述】:

在谈到 DOM 时,我一直对 HTMLCollections、对象和数组感到困惑。比如……

  1. document.getElementsByTagName("td")$("td") 有什么区别?
  2. $("#myTable")$("td") 是对象(jQuery 对象)。为什么console.log旁边还显示了DOM元素的数组,它们不是对象也不是数组吗?
  3. 什么是难以捉摸的“NodeLists”,我该如何选择?

还请提供对以下脚本的任何解释。

[123,"abc",321,"cba"]=[123,"abc",321,"cba"]
{123:123,abc:"abc",321:321,cba:"cba"}=Object { 123=123, abc="abc", 321=321, more...}
Node= Node { ELEMENT_NODE=1, ATTRIBUTE_NODE=2, TEXT_NODE=3, more...}
document.links= HTMLCollection[a #, a #]
document.getElementById("myTable")= <table id="myTable">
document.getElementsByClassName("myRow")= HTMLCollection[tr.myRow, tr.myRow]
document.getElementsByTagName("td")= HTMLCollection[td, td, td, td]
$("#myTable")= Object[table#myTable]
$("td")= Object[td, td, td, td]


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
    <head> 
        <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" /> 
        <title>Collections?</title>  
        <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script> 
        <script type="text/javascript">
            $(function(){
                console.log('[123,"abc",321,"cba"]=',[123,"abc",321,"cba"]);
                console.log('{123:123,abc:"abc",321:321,cba:"cba"}=',{123:123,abc:"abc",321:321,cba:"cba"});
                console.log('Node=',Node);
                console.log('document.links=',document.links);
                console.log('document.getElementById("myTable")=',document.getElementById("myTable"));
                console.log('document.getElementsByClassName("myRow")=',document.getElementsByClassName("myRow"))
                console.log('document.getElementsByTagName("td")=',document.getElementsByTagName("td"));
                console.log('$("#myTable")=',$("#myTable"));
                console.log('$("td")=',$("td"));
            });
        </script>
    </head>

    <body>
        <a href="#">Link1</a>
        <a href="#">Link2</a>
        <table id="myTable">
            <tr class="myRow"><td>td11</td><td>td12</td></tr>
            <tr class="myRow"><td>td21</td><td>td22</td></tr>
        </table>
    </body> 
</html>

【问题讨论】:

  • 我想我可能会为后代添加以下内容。 (a) 在现代 JavaScript 中,更好的比较是 document.querySelectorAll('td')$('td')。 (b) 基本的区别在于 jQuery 使用它自己的对象类型,其中包含 HTML 元素的 编号 集合;这个集合不是上述的,jQuery 对象本质上是一个真正的 DOM 元素的 wrapper

标签: javascript jquery dom


【解决方案1】:

首先我将解释NodeListHTMLCollection之间的区别。

这两个接口都是 DOM 节点的集合。它们在提供的方法和可以包含的节点类型上有所不同。虽然 NodeList 可以包含任何节点类型,但 HTMLCollection 应该只包含 Element 节点。
HTMLCollection 提供与NodeList 相同的方法,另外还有一个称为namedItem 的方法。

当必须向多个节点提供访问权限时,总是使用集合,例如大多数选择器方法(例如getElementsByTagName)返回多个节点或获取对所有子节点的引用(element.childNodes)。

欲了解更多信息,请查看DOM4 specification - Collections

document.getElementsByTagName("td")$("td") 有什么区别?

getElementsByTagName 是 DOM 接口的方法。它接受标签名称作为输入并返回HTMLCollection(参见DOM4 specification)。

$("td") 大概是 jQuery。它接受任何有效的 CSS/jQuery 选择器并返回一个 jQuery 对象。

标准 DOM 集合和 jQuery 选择之间的最大区别在于 DOM 集合通常是实时的(尽管并非所有方法都返回实时集合),即,如果他们受到影响。它们就像 DOM 树上的 视图,而 jQuery 选择是调用函数时 DOM 树的快照。

为什么console.log旁边还显示了DOM元素的数组,它们不是对象也不是数组吗?

jQuery 对象是 类数组 对象,即它们具有数字属性和 length 属性(请记住,数组本身就是对象)。浏览器倾向于以特殊的方式显示数组和类似数组的对象,例如[ ... , ... , ... ]

什么是难以捉摸的“NodeLists”,我该如何选择?

请参阅我的答案的第一部分。您不能选择 NodeLists,它们是选择的结果

据我所知,甚至没有办法以编程方式创建NodeLists(即创建一个空的并稍后添加节点),它们仅由某些 DOM 方法/属性返回。

【讨论】:

  • @user1032531:好吧,如果您对选定的 DOM 元素之一进行任何更改(例如添加一个子元素),那么您当然会看到更改,因为它是同一个 DOM 元素。但是,假设您选择了所有 td 元素,稍后添加新的 td 元素不会自动更新选择以包含新元素。
  • @FelixKling:您应该提到并非所有NodeLists 都在直播。
  • 我希望它们都是数组
  • NodeList 中似乎也有方法“keys”、“entries”和“forEach”,但在 HTMLCollection 中没有
  • @KrzysztofGrzybek 没错,而且非常烦人。为什么其中一个有.forEach() 而另一个没有?
【解决方案2】:

0。 HTMLCollectionNodeList 有什么区别?

这里有一些定义。

DOM Level 1 Spec - Miscellaneous Object Definitions:

接口 HTMLCollection

HTMLCollection 是一个节点列表。可以通过序号索引或节点的名称或 id 属性访问单个节点。注意:假定 HTML DOM 中的集合是实时的,这意味着当基础文档更改时它们会自动更新。

DOM Level 3 Spec - NodeList

接口节点列表

NodeList 接口提供了节点有序集合的抽象,而无需定义或限制该集合的实现方式。 DOM 中的 NodeList 对象是活动的。

NodeList 中的项目可通过整数索引访问,从 0 开始。

所以它们都可以包含实时数据,这意味着 DOM 将在它们的值发生时更新。它们还包含一组不同的函数。

如果您在运行脚本时检查控制台,您会注意到table DOM 元素同时包含childNodes NodeList[2]children HTMLCollection[1]。为什么它们不同?因为HTMLCollection只能包含元素节点,所以NodeList也包含一个文本节点。

1。 document.getElementsByTagName("td")$("td")有什么区别?

document.getElementsByTagName("td") 返回一个 DOM 元素数组(NodeList),$("td") 被称为 jQuery 对象,它的属性 012 具有来自 document.getElementsByTagName("td") 的元素等。主要区别在于 jQuery 对象的检索速度稍慢,但可以访问所有方便的 jQuery 函数。

2。 $("#myTable")$("td") 是对象(jQuery 对象)。为什么console.log旁边还显示了DOM元素的数组,它们不是对象也不是数组吗?

它们是属性012 等设置为DOM 元素的对象。这是一个简单的例子:它是如何工作的:

jsFiddle

    var a = {
        1: "first",
        2: "second"
    }
    alert(a[1]);

3。难以捉摸的“NodeLists”到底是什么,我该如何选择?

您一直在代码中检索它们,getElementsByClassNamegetElementsByTagName 都返回 NodeLists

【讨论】:

  • 您是如何在第三次响应中显示 DOM 的?谢谢!
  • @user1032531 是 Chrome 开发工具。顺便说一句,我更新了答案的开头。
  • 类似数组的日志主要是 length 属性的结果,而不是数字属性名称的结果。你提醒字符串的例子与console.log有什么关系?
  • 这展示了如何在对象上拥有数字属性。我试图强调它们是对象而不是数组的事实。
  • 3 号完全错误。 getElementsByClassName 和 getElementsByTagName 返回 HTMLCollections 而不是 NodeLists。 querySelector 和 querySelectorAll 将返回一个 NodeList。
【解决方案3】:

补充说明

HTMLCollection 和 NodeList 有什么区别?

HTMLCollection 仅包含元素节点(标签),NodeList 包含所有节点

最重要的节点类型:

  1. 元素节点
  2. 属性节点
  3. 文本节点
  4. 评论节点

node types

元素内的空白被视为文本,文本被视为节点。

考虑以下几点:

<ul id="myList">
  <!-- List items -->
  <li>List item 1</li> 
  <li>List item 2</li>
  <li>List item 3</li>
  <li>List item 4</li>
  <li>List item 5</li>
</ul>

空格:&lt;ul id="myList"&gt; &lt;li&gt;List item&lt;/li&gt;&lt;/ul&gt;

没有空格:&lt;ul id="myList"&gt;&lt;li&gt;List item&lt;/li&gt;&lt;/ul&gt;

【讨论】:

    【解决方案4】:

    已经讲了这么多,但想一个更概括的答案版本并举例说明HTMLCollectionNodeList 之间的区别会有所帮助。

    DOM 中的节点类型

    • 有 12 种不同的节点类型,可能有各种节点类型的子节点:

    • 我们可以使用以下三个属性来检查和查询 DOM 中的节点:

      • nodeType房产
      • nodeName房产
      • nodeValue房产
    • nodeType 属性以数字形式返回指定节点的节点类型。

      • 如果节点是元素节点,nodeType 属性将返回 1
      • 如果节点是属性节点,nodeType 属性将返回 2
      • 如果节点是文本节点,nodeType 属性将返回 3
      • 如果节点是评论节点,nodeType 属性将返回 8
      • 此属性是只读的。

    HTMLCollection 与 NodeList

    我们可以通过以下示例更清楚地了解HTMLCollectionNodeList 之间的区别。请尝试在您自己的浏览器控制台中检查输出以更好地理解。

    <ul>
      <li>foo</li>
      <li>bar</li>
      <li>bar</li>
    </ul>
    
    // retrieve element using querySelectorAll
    const listItems_querySelector = document.querySelectorAll('li');
    console.log('querySelector', listItems_querySelector);
    
    // retrieve element using childNodes
    const list  = document.querySelector('ul')
    const listItems_childNodes = list.childNodes;
    console.log('childNodes', listItems_childNodes);
    const listItems_children = list.children;
    console.log('children', listItems_children);
    
    const listItems_getElementsByTagName = document.getElementsByTagName('li');
    console.log('getElementsByTagName', listItems_getElementsByTagName);
    
    console.log('*************************');
    console.log('add one list item');
    console.log('*************************');
    list.appendChild(document.createElement('li'));
    
    console.log('querySelector', listItems_querySelector);
    console.log('childNodes', listItems_childNodes);
    console.log('children', listItems_children);
    console.log('getElementsByTagName', listItems_getElementsByTagName);
    
    console.log('*************************');
    console.log('add one more list item');
    console.log('*************************');
    listItems_getElementsByTagName[0].parentNode.appendChild(document.createElement('li'));
    
    console.log('querySelector', listItems_querySelector);
    console.log('childNodes', listItems_childNodes);
    console.log('children', listItems_children);
    console.log('getElementsByTagName', listItems_getElementsByTagName); 
    

    【讨论】:

      【解决方案5】:

      $("td") 是扩展的 jQuery 对象,它具有 jQuery 方法,它返回包含 html 对象数组的 jquery 对象。 document.getElementsByTagName("td") 是原始 js 方法并返回 NodeList。 See this article

      【讨论】:

      • 感谢 Karaxuna。是的,我看过那篇文章。不知道它是否有帮助,但肯定让我问了更多问题:)
      • 谢谢@karaxuna。有用的文章,解释得很好。
      【解决方案6】:

      NodeList 对象是 Node 的集合,例如通过 x.childNodes 属性或 document.querySelectorAll() 方法返回。在某些情况下,NodeList 是 live,这意味着 DOM 中的更改会自动更新集合!例如,Node.childNodes 是实时的:

      var c = parent.childNodes; //assume c.length is 2
      parent.appendChild(document.createElement('div'));
      //now c.length is 3, despite the `c` variable is assigned before appendChild()!!
      //so, do not cache the list's length in a loop.
      

      但在其他一些情况下,NodeList 是静态的,其中 DOM 中的任何更改都不会影响集合的内容。 querySelectorAll() 返回一个静态 NodeList。

      HTMLCollection 是一个实时且有序 的元素集合(当基础文档更改时它会自动更新)。它可以是children 之类的属性或document.getElementsByTagName() 之类的方法的结果,并且只能将HTMLElement's 作为它们的项目。

      HTMLCollection 还通过名称和索引将其成员直接公开为属性:

      var f = document.forms; // this is an HTMLCollection
      f[0] === f.item(0) === f.myForm //assume first form id is 'myForm'
      

      HTMLElement 只是节点的一种类型:

      节点可以是several types。最重要的如下:

      • element (1):一个 Element 节点,例如 &lt;p&gt;&lt;div&gt;
      • 属性 (2):元素的属性。元素属性不再实现 DOM4 规范中的 Node 接口!
      • text (3):元素或属性的实际文本。
      • comment (8):一个评论节点。
      • document (9):一个文档节点。

      所以,一个很大的区别是 HTMLCollection 只包含 HTMLElements 但 NodeList 还包含 cmets、空白文本(回车符、空格..)等。检查它如下 sn-p:

      function printList(x, title) {
        console.log("\r\nprinting "+title+" (length="+x.length+"):");
        for(var i=0; i<x.length; i++) {
          console.log("  "+i+":"+x[i]);
        }
      }
      
      var elems = document.body.children; //HTMLCollection
      var nodes = document.body.childNodes; //NodeList
      
      printList(elems, "children [HTMLCollection]");
      printList(nodes, "childNodes [NodeList]");
      <div>para 1</div><!-- MyComment -->
      <div>para 2</div>

      HTMLCollection 和 NodeList 都包含 length 属性,您可以使用它来循环它们的项目。不要使用 for...in 或 for each...in 来枚举 NodeLists 中的项目,因为如果您的脚本假定它只需要处理元素对象,它们也会枚举其长度和项目属性并导致错误。此外,for..in 不保证以任何特定顺序访问属性。

      for (var i = 0; i < myNodeList.length; i++) {
        var item = myNodeList[i];
      }
      

      【讨论】:

        猜你喜欢
        • 2019-11-01
        • 2015-06-24
        • 1970-01-01
        • 2012-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-15
        • 2011-07-13
        相关资源
        最近更新 更多