HTMLCollection,NodeList和对象数组之间的区别


94

对于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元素的包装
曼戈

Answers:


113

首先,我将解释之间的差异NodeListHTMLCollection

两个接口是集合DOM节点。它们在提供的方法和可以包含的节点类型方面有所不同。虽然NodeList可以包含任何节点类型,但是HTMLCollection假定仅包含元素节点。
一个HTMLCollection提供相同的方法作为一个NodeList和另外一个被调用的方法namedItem

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

有关更多信息,请查看DOM4规范-Collections

document.getElementsByTagName("td")和之间有什么区别$("td")

getElementsByTagName是DOM接口的方法。它接受标记名称作为输入并返回HTMLCollection(请参阅DOM4规范)。

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

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

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

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

什么是难以捉摸的“ NodeLists”,以及如何选择一个?

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

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


2
@ user1032531:好吧,如果您对选定的DOM元素之一进行了任何更改(例如,添加一个子元素),那么您当然会看到该更改,因为它是一个相同的DOM元素。但是,假设您选择了所有td元素,td以后再添加新元素将不会自动更新选择内容以包含新元素。
Felix Kling 2013年

2
@FelixKling:您应该提到并非所有NodeLists都是实时的。
Bergi

2
我希望它们都是数组
SuperUberDuper

7
我似乎还发现NodeList中存在方法“ keys”,“ entries”和“ forEach”,但HTMLCollection中却没有
Krzysztof Grzybek

2
@KrzysztofGrzybek没错,这很烦人。为什么其中一个拥有.forEach()而另一个却没有呢?
Robo Robok

30

0. anHTMLCollection和a和有NodeList什么区别?

这是给您的一些定义。

DOM级别1规范-其他对象定义

界面HTMLCollection

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

DOM 3级规范-NodeList

接口节点列表

NodeList接口提供节点的有序集合的抽象,而无需定义或约束该集合的实现方式。DOM中的NodeList对象处于活动状态。

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

因此它们都可以包含实时数据,这意味着DOM将在其值更新时进行更新。它们还包含一组不同的功能。

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

在此处输入图片说明

1.document.getElementsByTagName("td")和之间有什么区别$("td")

document.getElementsByTagName("td")返回DOM元件的阵列(一NodeList),$("td")被称为jQuery对象从具有所述元件document.getElementsByTagName("td")上其属性012等,主要的区别是,jQuery对象较慢检索一点点,但可以访问所有的方便jQuery函数。

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

他们对自己的属性的对象012等一系列的DOM元素。这是一个简单的示例:其工作方式:

jsFiddle

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

3.难以理解的“ NodeLists”是什么,我该如何选择一个?

您一直在代码中检索它们,getElementsByClassName并且getElementsByTagName都返回NodeLists

节点列表


您如何在第三个响应中显示DOM?谢谢!
user1032531 2013年

@ user1032531是Chrome开发者工具。顺便说一下,我更新了答案的开头。
Daniel Imms

类似数组的日志主要是length属性的结果,而不是数字属性的名称。与您的警报字符串示例有什么关系console.log
Bergi

那说明了如何在对象上具有数字属性。我试图强调事实,它们是对象,而不是数组。
Daniel Imms

9

补充说明

HTMLCollection和NodeList有什么区别?

的HTMLCollection只包含元素节点(标签)和节点列表包含了所有的节点

有四种节点类型:

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

nodeTypes

元素内部的空格被视为文本,而文本被视为节点。

考虑以下:

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

空格: <ul id="myList"> <li>List item</li></ul>

无空格: <ul id="myList"><li>List item</li></ul>

HTMLCollection和NodeList之间的区别


2

$("td")是扩展的jQuery对象,并且具有jQuery方法,它返回包含html对象数组的jquery对象。document.getElementsByTagName("td")是原始的js方法,并返回NodeList。看这篇文章


谢谢Karaxuna。是的,我看了那篇文章。不知道它是否有帮助,但是绝对让我问了更多问题:)
2013年

谢谢@karaxuna。有用的文章,很好解释。
朱塞佩2015年

0

节点列表对象是节点的集合,通过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是一个活的和有序的元素集合(在底层的文件被更改,自动更新)。它可以是诸如子代之类的属性或诸如document.getElementsByTagName()之类的方法的结果,并且只能以HTMLElement作为其项。

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

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

HTMLElement只是节点的一种类型:

节点<< HTMLElement继承

节点可以是几种类型。最重要的如下:

  • element(1):元素节点,例如<p><div>
  • attribute(2):元素的属性。元素属性不再实现DOM4规范中的Node接口!
  • 文字(3):元素或属性的实际文字。
  • comment(8):评论节点。
  • document(9):文档节点。

因此,最大的区别是HTMLCollection仅包含HTMLElements,而NodeList也包含注释,空格文本(回车符,空格..)等。请按照以下代码段进行检查:

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属性,您可以使用该属性来循环其项。不要使用... in或for每个... in来枚举NodeLists中的项目,因为它们也会枚举其长度和项目属性,并且如果您的脚本假定它只需要处理元素对象,则会导致错误。另外,不能保证for..in会以任何特定顺序访问属性。

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

0

这么多已被告知了,但想到答案更概括版本为例来解释之间的差异HTMLCollection,并NodeList会有所帮助。

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); 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.