สำหรับคำตอบนี้ผมหมายถึงquerySelector
และquerySelectorAll
เป็น querySelector * และเพื่อgetElementById
, getElementsByClassName
, getElementsByTagName
และgetElementsByName
เป็น getElement *
ความแตกต่างหลัก
- querySelector * มีความยืดหยุ่นมากขึ้นเนื่องจากคุณสามารถส่งผ่านตัวเลือก CSS3 ใด ๆ ได้ไม่ใช่แค่ตัวเลือกง่ายๆสำหรับ id แท็กหรือคลาส
- ประสิทธิภาพของ querySelectorจะเปลี่ยนตามขนาดของ DOM ที่ถูกเรียกใช้* เพื่อความแม่นยำการเรียก querySelector * จะทำงานในเวลา O (n) และการเรียก getElement * จะทำงานในเวลา O (1) โดยที่ n คือจำนวนทั้งหมดของลูกทั้งหมดขององค์ประกอบหรือเอกสารที่เรียกใช้ ความจริงเรื่องนี้ดูเหมือนจะเป็นที่รู้จักน้อยที่สุดดังนั้นฉันจึงถือมัน
- การเรียก getElement * คืนการอ้างอิงโดยตรงไปยัง DOM ในขณะที่ querySelector * สร้างสำเนาภายในขององค์ประกอบที่เลือกไว้ก่อนที่จะส่งกลับการอ้างอิงถึงพวกเขา สิ่งเหล่านี้เรียกว่าองค์ประกอบ "สด" และ "คงที่" สิ่งนี้ไม่เกี่ยวข้องกับประเภทที่ส่งคืนอย่างเคร่งครัด ไม่มีทางที่ฉันจะรู้ว่าองค์ประกอบนั้นเป็นรายการสดหรือเป็นแบบคงที่โดยทางโปรแกรมขึ้นอยู่กับว่าองค์ประกอบถูกคัดลอกในบางจุดและไม่ได้เป็นคุณสมบัติที่แท้จริงของข้อมูล การเปลี่ยนแปลงองค์ประกอบที่ใช้งานจะมีผลทันที - การเปลี่ยนแปลงองค์ประกอบที่มีการเปลี่ยนแปลงจะเปลี่ยนแปลงโดยตรงใน DOM และดังนั้นบรรทัดถัดไปของ JS จะเห็นการเปลี่ยนแปลงนั้นและจะเผยแพร่ไปยังองค์ประกอบอื่น ๆ ที่อ้างอิงองค์ประกอบนั้นทันที การเปลี่ยนแปลงองค์ประกอบแบบสแตติกจะถูกเขียนกลับไปที่ DOM หลังจากสคริปต์ปัจจุบันดำเนินการเสร็จสิ้น
- ผลตอบแทนประเภทของสายเหล่านี้แตกต่างกันไป
querySelector
และgetElementById
ทั้งสองส่งคืนองค์ประกอบเดียว querySelectorAll
และgetElementsByName
ทั้งสองกลับ NodeLists เป็นฟังก์ชั่นใหม่ที่ถูกเพิ่มเข้ามาหลังจากที่ HTMLCollection ล้าสมัยไปแล้ว HTMLC ที่เก่ากว่าgetElementsByClassName
และgetElementsByTagName
ทั้งคู่ส่งคืน HTMLCollections อีกครั้งนี้เป็นหลักไม่เกี่ยวข้องกับองค์ประกอบที่มีชีวิตอยู่หรือคงที่
แนวคิดเหล่านี้ถูกสรุปไว้ในตารางต่อไปนี้
Function | Live? | Type | Time Complexity
querySelector | N | Element | O(n)
querySelectorAll | N | NodeList | O(n)
getElementById | Y | Element | O(1)
getElementsByClassName | Y | HTMLCollection | O(1)
getElementsByTagName | Y | HTMLCollection | O(1)
getElementsByName | Y | NodeList | O(1)
รายละเอียดเคล็ดลับและตัวอย่าง
HTMLCollections ไม่เหมือนอาร์เรย์เหมือน NodeLists และไม่สนับสนุน. forEach () ฉันพบว่าตัวดำเนินการสเปรดมีประโยชน์ในการแก้ไขปัญหานี้:
[...document.getElementsByClassName("someClass")].forEach()
ทุกองค์ประกอบและทั่วโลกdocument
มีการเข้าถึงทุกฟังก์ชั่นเหล่านี้ยกเว้นgetElementById
และซึ่งจะดำเนินการเฉพาะในgetElementsByName
document
การเรียกใช้ getElement * Chaining แทนการใช้ querySelector * จะปรับปรุงประสิทธิภาพโดยเฉพาะใน DOM ที่มีขนาดใหญ่มาก แม้แต่ใน DOM ขนาดเล็กและ / หรือด้วยโซ่ที่ยาวมากโดยทั่วไปจะเร็วกว่า อย่างไรก็ตามถ้าคุณไม่ทราบว่าคุณต้องการประสิทธิภาพการทำงานควรอ่านความต้องการของ querySelector * querySelectorAll
มักจะยากที่จะเขียนซ้ำเพราะคุณต้องเลือกองค์ประกอบจาก NodeList หรือ HTMLCollection ในทุกขั้นตอน ตัวอย่างเช่นรหัสต่อไปนี้ใช้งานไม่ได้ :
document.getElementsByClassName("someClass").getElementsByTagName("div")
because you can only use getElements* on single elements, not collections. For example:
`document.querySelector("#someId .someClass div")`
could be written as:
document.getElementById("someId").getElementsByClassName("someClass")[0].getElementsByTagName("div")[0]
Note the use of `[0]` to get just the first element of the collection at each step that returns a collection, resulting in one element at the end just like with `querySelector`.
เนื่องจากองค์ประกอบทั้งหมดมีการเข้าถึงทั้งการสืบค้น querySelector * และ getElement * คุณสามารถทำการโยงโดยใช้การโทรทั้งสองซึ่งอาจมีประโยชน์หากคุณต้องการประสิทธิภาพที่เพิ่มขึ้น แต่ไม่สามารถหลีกเลี่ยงการ querySelector ที่ไม่สามารถเขียนในแง่ของการโทร getElement * .
แม้ว่าโดยทั่วไปจะง่ายต่อการบอกว่าตัวเลือกสามารถเขียนได้โดยใช้การเรียก getElement * เท่านั้น แต่มีบางกรณีที่อาจไม่ชัดเจน:
document.querySelectorAll(".class1.class2")
สามารถเขียนใหม่เป็น
document.getElementsByClassName("class1 class2")
การใช้ getElement * บนองค์ประกอบคงที่ที่ดึงมาด้วย querySelector * จะส่งผลให้องค์ประกอบที่มีชีวิตอยู่ด้วยความเคารพต่อชุดย่อยคงที่ของ DOM คัดลอกโดย querySelector แต่ไม่ได้อยู่กับความเคารพในเอกสารเต็ม DOM ... นี่คือที่ง่าย การตีความองค์ประกอบ / สดคงที่เริ่มกระจุย คุณควรหลีกเลี่ยงสถานการณ์ที่คุณต้องกังวลเกี่ยวกับเรื่องนี้ แต่ถ้าคุณทำโปรดจำไว้ว่า querySelector * เรียกองค์ประกอบการคัดลอกที่พวกเขาพบก่อนที่จะส่งกลับการอ้างอิงถึงพวกเขา แต่การเรียก getElement * เรียกการอ้างอิงโดยตรงโดยไม่คัดลอก
API จะไม่ระบุองค์ประกอบที่ควรเลือกก่อนหากมีการแข่งขันหลายรายการ
เนื่องจาก querySelector * ทำซ้ำผ่าน DOM จนกว่าจะพบการแข่งขัน (ดูความแตกต่างหลัก # 2) ข้างต้นก็หมายความว่าคุณไม่สามารถพึ่งพาตำแหน่งขององค์ประกอบที่คุณกำลังมองหาใน DOM เพื่อรับประกันว่าจะพบได้อย่างรวดเร็ว - เบราว์เซอร์อาจทำซ้ำผ่าน DOM ย้อนกลับไปข้างหน้าลึกก่อนกว้างหรืออื่น ๆ getElement * จะยังคงค้นหาองค์ประกอบในเวลาประมาณเดียวกันโดยไม่คำนึงถึงตำแหน่ง