ความแตกต่างระหว่าง HTMLCollection, NodeLists และอาร์เรย์ของวัตถุ


94

ฉันสับสนระหว่าง HTMLCollections วัตถุและอาร์เรย์เสมอเมื่อพูดถึง DOM เช่น ...

  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>

ฉันคิดว่าฉันอาจเพิ่มสิ่งต่อไปนี้สำหรับลูกหลาน (ก) ในปัจจุบัน JavaScript, การเปรียบเทียบที่ดีกว่าจะอยู่ระหว่างและdocument.querySelectorAll('td') $('td')(b) ความแตกต่างพื้นฐานคือ jQuery ทำงานร่วมกับประเภทของอ็อบเจ็กต์ของตัวเองซึ่งมีคอลเลกชันที่เป็นตัวเลขขององค์ประกอบ HTML คอลเลคชันนี้ไม่ใช่สิ่งที่กล่าวมาข้างต้นและออบเจ็กต์ jQuery นั้นเป็นสิ่งที่ห่อหุ้มองค์ประกอบ DOM ที่แท้จริง
Manngo

คำตอบ:


113

ครั้งแรกที่ฉันจะอธิบายความแตกต่างระหว่างและNodeListHTMLCollection

อินเทอร์เฟซทั้งสองเป็นคอลเลกชันของโหนด DOM พวกเขาแตกต่างกันในวิธีการที่มีให้และประเภทของโหนดที่สามารถมีได้ แม้ว่าNodeListสามารถมีโหนดประเภทใดก็ได้ แต่HTMLCollectionควรมีโหนดองค์ประกอบเท่านั้น ให้วิธีการเช่นเดียวกับและนอกจากนี้วิธีการที่เรียกว่า
HTMLCollectionNodeListnamedItem

คอลเลกชันจะถูกใช้เสมอเมื่อต้องมีการเข้าถึงหลายโหนดเช่นวิธีการเลือกส่วนใหญ่ (เช่นgetElementsByTagName) ส่งคืนหลายโหนดหรือรับการอ้างอิงถึงชายด์ทั้งหมด ( element.childNodes)

สำหรับข้อมูลเพิ่มเติมดูได้ที่สเปค DOM4 - คอลเลกชัน

อะไรคือความแตกต่างระหว่าง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" ที่เข้าใจยากคืออะไรและฉันจะเลือกได้อย่างไร

ดูส่วนแรกของคำตอบของฉัน คุณไม่สามารถเลือก NodeList s ได้ซึ่งเป็นผลมาจากการเลือก

เท่าที่ฉันรู้ไม่มีแม้แต่วิธีสร้าง NodeList s แบบเป็นโปรแกรม (เช่นการสร้างโหนดว่างและเพิ่มโหนดในภายหลัง) พวกเขาจะถูกส่งคืนโดยวิธี / คุณสมบัติ DOM บางอย่างเท่านั้น


2
@ user1032531: ถ้าคุณทำการเปลี่ยนแปลงใด ๆ กับหนึ่งในองค์ประกอบ DOM ที่เลือก (เช่นการเพิ่มลูก) แน่นอนว่าคุณจะเห็นการเปลี่ยนแปลงเนื่องจากเป็นองค์ประกอบ DOM เดียวและเหมือนกัน แต่สมมติว่าคุณเลือกtdองค์ประกอบทั้งหมดการเพิ่มtdองค์ประกอบใหม่ในภายหลังจะไม่อัปเดตการเลือกโดยอัตโนมัติเพื่อให้มีองค์ประกอบใหม่
Felix Kling

2
@FelixKling: คุณควรพูดว่าไม่ใช่ทุกคนNodeListที่มีชีวิตอยู่
Bergi

2
ฉันหวังว่าพวกเขาจะเป็นอาร์เรย์ทั้งหมด
SuperUberDuper

7
ดูเหมือนว่า method "keys", "entries" และ "forEach" จะปรากฏใน NodeList แต่ไม่มีใน HTMLCollection
Krzysztof Grzybek

2
@KrzysztofGrzybek ใช่แล้วมันน่ารำคาญสุด ๆ ทำไมห่าหนึ่งในนั้นมี.forEach()และอีกอันไม่มี?
Robo Robok

30

0. an HTMLCollectionกับ a ต่างกันNodeListอย่างไร?

นี่คือคำจำกัดความสำหรับคุณ

ข้อมูลจำเพาะ DOM ระดับ 1 - นิยามวัตถุเบ็ดเตล็ด :

อินเทอร์เฟซ HTMLCollection

HTMLCollection คือรายการของโหนด แต่ละโหนดสามารถเข้าถึงได้โดยดัชนีลำดับหรือชื่อของโหนดหรือแอตทริบิวต์ id หมายเหตุ: คอลเลกชันใน HTML DOM จะถือว่าเป็นแบบสดซึ่งหมายความว่าจะมีการอัปเดตโดยอัตโนมัติเมื่อมีการเปลี่ยนแปลงเอกสารพื้นฐาน

ข้อมูลจำเพาะ DOM ระดับ 3 - NodeList

NodeList ของอินเทอร์เฟซ

อินเทอร์เฟซ NodeList จัดเตรียมส่วนที่เป็นนามธรรมของคอลเลกชันที่เรียงลำดับของโหนดโดยไม่กำหนดหรือ จำกัด วิธีการใช้งานคอลเล็กชันนี้ อ็อบเจ็กต์ NodeList ใน DOM ใช้งานได้

รายการใน NodeList สามารถเข้าถึงได้ผ่านดัชนีอินทิกรัลโดยเริ่มจาก 0

ดังนั้นทั้งสองจึงสามารถมีข้อมูลสดซึ่งหมายความว่า DOM จะอัปเดตเมื่อค่าของพวกเขาเสร็จสิ้น นอกจากนี้ยังมีชุดฟังก์ชันที่แตกต่างกัน

คุณจะทราบว่าคุณตรวจสอบคอนโซลหรือไม่หากคุณเรียกใช้สคริปต์ของคุณว่าtableองค์ประกอบ DOM มีทั้ง a childNodes NodeList[2]และ a children HTMLCollection[1]. ทำไมพวกเขาถึงแตกต่างกัน? เนื่องจากHTMLCollectionสามารถมีได้เฉพาะโหนดองค์ประกอบ NodeList จึงมีโหนดข้อความ

ป้อนคำอธิบายภาพที่นี่

1. อะไรคือความแตกต่างระหว่างdocument.getElementsByTagName("td")และ$("td")?

document.getElementsByTagName("td")ผลตอบแทนอาร์เรย์ขององค์ประกอบ DOM (กNodeList) $("td")จะเรียกว่าเป็นวัตถุ jQuery ซึ่งมีองค์ประกอบจากdocument.getElementsByTagName("td")เกี่ยวกับคุณสมบัติของมัน0, 1, 2ฯลฯ ความแตกต่างที่สำคัญคือวัตถุ jQuery เป็นเล็ก ๆ น้อย ๆ ช้าลงเพื่อดึง แต่ให้เข้าถึงทุกที่มีประโยชน์ ฟังก์ชัน jQuery

2. $("#myTable")และ$("td")เป็นวัตถุ ( jQueryวัตถุ) ทำไมconsole.logแสดงอาร์เรย์ขององค์ประกอบ DOM ที่อยู่ข้างๆพวกเขาด้วยและไม่ใช่วัตถุไม่ใช่อาร์เรย์

พวกเขาเป็นวัตถุที่มีคุณสมบัติของพวกเขา0, 1, 2ฯลฯ ชุดองค์ประกอบ DOM นี่คือตัวอย่างง่ายๆ: วิธีการทำงาน:

jsFiddle

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

3. "NodeLists" ที่เข้าใจยากคืออะไรและฉันจะเลือกได้อย่างไร

คุณได้รับข้อมูลเหล่านี้ในรหัสของคุณgetElementsByClassNameและgetElementsByTagNameทั้งสองกลับNodeLists

NodeList


คุณแสดง DOM ในการตอบกลับครั้งที่ 3 อย่างไร ขอบคุณ!
user1032531

@ user1032531 นั่นคือเครื่องมือ Chrome dev ฉันอัปเดตจุดเริ่มต้นของคำตอบแล้ว
Daniel Imms

บันทึกที่เหมือนอาร์เรย์ส่วนใหญ่เป็นผลมาจากlengthคุณสมบัติไม่ใช่จากชื่อคุณสมบัติที่เป็นตัวเลข และตัวอย่างการแจ้งเตือนสตริงของคุณเกี่ยวข้องกับconsole.logอะไร?
Bergi

นั่นแสดงให้เห็นว่าคุณมีคุณสมบัติเป็นตัวเลขบนวัตถุได้อย่างไร ฉันพยายามเน้นข้อเท็จจริงที่ว่าพวกมันเป็นวัตถุไม่ใช่อาร์เรย์
Daniel Imms

9

หมายเหตุเพิ่มเติม

อะไรคือความแตกต่างระหว่าง HTMLCollection และ NodeList?

HTMLCollectionมีโหนดองค์ประกอบเท่านั้น ( แท็ก ) และNodeListมีทุกโหนด

โหนดมีสี่ประเภท:

  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 ซึ่งจะส่งคืนวัตถุ jquery ที่มีอาร์เรย์ของวัตถุ html document.getElementsByTagName("td")เป็นเมธอด raw js และส่งคืน NodeList ดูบทความนี้


ขอบคุณ Karaxuna ใช่ฉันได้ดูบทความนั้นแล้ว ไม่รู้ว่ามันช่วยได้ไหม แต่ทำให้ฉันถามคำถามเพิ่มเติมได้แน่นอน :)
user1032531

ขอบคุณ @karaxuna บทความที่เป็นประโยชน์อธิบายได้ดีมาก
Giuseppe

0

NodeListวัตถุคอลเลกชันของโหนดกลับเช่นโดย x childNodesคุณสมบัติหรือdocument.querySelectorAll ()วิธีการ ในบางกรณี NodeList จะใช้งานได้ซึ่งหมายความว่าการเปลี่ยนแปลงใน 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

โหนดสามารถเป็นหลายประเภท สิ่งที่สำคัญที่สุดมีดังต่อไปนี้:

  • องค์ประกอบ (1): องค์ประกอบโหนดเช่นหรือ<p><div>
  • แอตทริบิวต์ (2): แอตทริบิวต์ขององค์ประกอบ แอตทริบิวต์องค์ประกอบไม่ได้ใช้อินเทอร์เฟซโหนดในข้อกำหนด DOM4 อีกต่อไป!
  • text (3): ข้อความจริงขององค์ประกอบหรือแอตทริบิวต์
  • ความคิดเห็น (8): โหนดความคิดเห็น
  • เอกสาร (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 มีคุณสมบัติความยาวที่คุณสามารถใช้เพื่อวนซ้ำรายการของพวกเขา อย่าใช้สำหรับ ... ในหรือสำหรับแต่ละ ... ในเพื่อแจกแจงรายการใน NodeLists เนื่องจากจะแจกแจงความยาวและคุณสมบัติของรายการและทำให้เกิดข้อผิดพลาดหากสคริปต์ของคุณถือว่าต้องจัดการกับออบเจ็กต์องค์ประกอบเท่านั้น นอกจากนี้สำหรับ.. ในไม่รับประกันว่าจะเข้าชมคุณสมบัติตามลำดับใด ๆ

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

0

มีคนบอกไปแล้วมากมาย แต่ลองคิดคำตอบแบบสรุปเพิ่มเติมพร้อมตัวอย่างเพื่ออธิบายความแตกต่างระหว่าง HTMLCollectionและNodeListจะช่วยได้

ประเภทของโหนดใน DOM

  • มีโหนด 12 ประเภทที่แตกต่างกันซึ่งอาจมีลูกของโหนดประเภทต่างๆ:

ป้อนคำอธิบายภาพที่นี่

  • เราสามารถใช้คุณสมบัติสามประการต่อไปนี้เพื่อตรวจสอบและสอบถามเกี่ยวกับโหนดใน DOM:

    • nodeType ทรัพย์สิน
    • nodeName ทรัพย์สิน
    • nodeValue ทรัพย์สิน
  • nodeTypeคุณสมบัติผลตอบแทนประเภทโหนดที่เป็นหมายเลขของโหนดที่ระบุ

    • ถ้าโหนดเป็นโหนดองค์ประกอบnodeTypeคุณสมบัติจะส่งคืน1 1
    • ถ้าโหนดเป็นโหนดแอตทริบิวต์nodeTypeคุณสมบัติจะส่งคืน2 2
    • ถ้าโหนดเป็นโหนดข้อความnodeTypeคุณสมบัติจะส่งคืน3 3
    • ถ้าโหนดเป็นโหนดข้อคิดเห็นnodeTypeคุณสมบัติจะส่งคืน8 8
    • คุณสมบัตินี้เป็นแบบอ่านอย่างเดียว

HTMLCollection กับ NodeList

ป้อนคำอธิบายภาพที่นี่

เราสามารถเข้าใจความแตกต่างระหว่างHTMLCollectionและNodeListชัดเจนมากขึ้นด้วยตัวอย่างต่อไปนี้ โปรดลองตรวจสอบผลลัพธ์ในคอนโซลเบราว์เซอร์ของคุณเองเพื่อความเข้าใจที่ดีขึ้น

<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); 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.