querySelector dan querySelectorAll vs getElementsByClassName dan getElementById di JavaScript

165

Saya ingin tahu apa sebenarnya perbedaan antara querySelectordan querySelectorAllmelawan getElementsByClassNamedan getElementById?

Dari tautan ini saya dapat mengumpulkan bahwa dengan querySelectorsaya dapat menulis document.querySelector(".myclass")untuk mendapatkan elemen dengan kelas myclassdan document.querySelector("#myid")untuk mendapatkan elemen dengan ID myid. Tapi saya sudah bisa melakukan itu getElementsByClassNamedan getElementById. Yang mana yang lebih disukai?

Saya juga bekerja di XPages di mana ID dihasilkan secara dinamis dengan titik dua dan terlihat seperti ini view:_id1:inputText1. Jadi ketika saya menulis document.querySelector("#view:_id1:inputText1")itu tidak berhasil. Tetapi menulis document.getElementById("view:_id1:inputText1")berhasil. Ada ide mengapa?

Naveen
sumber
1
querySelector digunakan untuk menanyakan pohon HTML DOM yang dapat memasukkan elemen html dan atributnya sebagai elemen kunci untuk permintaan ... Anda dapat menggunakan ekspresi reguler untuk mencapai ini .. dojo.query () melakukan hal yang sama
anix
1
Bukankah maksud Anda document.querySelectorAll(".myclass")? Menggunakan document.querySelector(".myclass")hanya akan mengembalikan elemen pertama yang cocok.
mhatch

Jawaban:

113

Saya ingin tahu apa sebenarnya perbedaan antara querySelector dan querySelectorAll terhadap getElementsByClassName dan getElementById?

Sintaks dan dukungan browser.

querySelector lebih berguna ketika Anda ingin menggunakan penyeleksi yang lebih kompleks.

mis. Semua item daftar diturunkan dari elemen yang merupakan anggota kelas foo: .foo li

document.querySelector ("# view: _id1: inputText1") tidak berfungsi. Tetapi menulis document.getElementById ("view: _id1: inputText1") berfungsi. Ada ide mengapa?

The :karakter memiliki arti khusus dalam pemilih. Anda harus menghindarinya. (Karakter pemilih melarikan diri memiliki arti khusus dalam string JS juga, jadi Anda harus melarikan diri itu juga).

document.querySelector("#view\\:_id1\\:inputText1")
Quentin
sumber
3
Ini akan bervariasi dari browser ke browser (dan dari versi ke versi). Saya akan berasumsi bahwa yang berbasis pemilih lebih mahal (tetapi tidak dengan cara yang akan cenderung signifikan)
Quentin
1
Saya mendukung pernyataan @ janaspage. Situs turun hari ini juga.
doplumi
6
Dan tentang pemilihan kelas lihat juga jsperf.com/getelementsbyclassname-vs-queryselectorall/25 . Kesimpulan: orang harus jauh lebih memilih javascript murni daripada jquery, dan fungsi spesifik getElementByIddan getElementsByClassName. Pilihan className bisa menjadi beberapa ratus kali lebih lambat tanpa getElementsByClassName.
Atrahasis
101

mengumpulkan dari Dokumentasi Mozilla:

Antarmuka NodeSelector Spesifikasi ini menambahkan dua metode baru ke objek yang mengimplementasikan antarmuka Dokumen, DocumentFragment, atau Elemen:

kueriSelektor

Mengembalikan simpul Elemen pencocokan pertama dalam subtree node. Jika tidak ada simpul yang cocok ditemukan, null dikembalikan.

querySelectorAll

Mengembalikan NodeList yang berisi semua simpul Elemen yang cocok dalam subtree node, atau NodeList kosong jika tidak ada kecocokan yang ditemukan.

dan

Catatan: NodeList yang dikembalikan oleh querySelectorAll()tidak langsung, yang berarti bahwa perubahan DOM tidak tercermin dalam koleksi. Ini berbeda dari metode kueri DOM lain yang mengembalikan daftar simpul langsung.

diEcho
sumber
32
+1 untuk menunjukkan perbedaan daftar simpul langsung. Itu perbedaan yang sangat penting untuk diperhatikan tergantung pada bagaimana Anda ingin menggunakan hasilnya.
jmbpiano
7
"live" berarti simpul yang ditambahkan dalam runtime DOM dan dapat bekerja pada simpul yang ditambahkan newley
diEcho
83

Tentang perbedaan, ada yang penting dalam hasil antara querySelectorAlldan getElementsByClassName: nilai kembali berbeda. querySelectorAllakan mengembalikan koleksi statis, sementara getElementsByClassNamemengembalikan koleksi langsung. Ini dapat menyebabkan kebingungan jika Anda menyimpan hasil dalam variabel untuk digunakan nanti:

  • Variabel yang dihasilkan dengan querySelectorAllakan berisi elemen yang memenuhi pemilih pada saat metode dipanggil .
  • Variabel yang dihasilkan dengan getElementsByClassNameakan berisi elemen-elemen yang memenuhi pemilih ketika digunakan (yang mungkin berbeda dari saat metode dipanggil).

Sebagai contoh, perhatikan bagaimana bahkan jika Anda belum menetapkan ulang variabel aux1dan aux2, mereka mengandung nilai yang berbeda setelah memperbarui kelas:

// storing all the elements with class "blue" using the two methods
var aux1 = document.querySelectorAll(".blue");
var aux2 = document.getElementsByClassName("blue");

// write the number of elements in each array (values match)
console.log("Number of elements with querySelectorAll = " + aux1.length);
console.log("Number of elements with getElementsByClassName = " + aux2.length);

// change one element's class to "blue"
document.getElementById("div1").className = "blue";

// write the number of elements in each array (values differ)
console.log("Number of elements with querySelectorAll = " + aux1.length);
console.log("Number of elements with getElementsByClassName = " + aux2.length);
.red { color:red; }
.green { color:green; }
.blue { color:blue; }
<div id="div0" class="blue">Blue</div>
<div id="div1" class="red">Red</div>
<div id="div2" class="green">Green</div>

Alvaro Montoro
sumber
2
Hanya untuk menyebutkan - Semua apis DOM lama mengembalikan daftar simpul yaitu document.getElementsByName, document.getElementsByTagNameNSatau document.getElementsByTagNameakan menunjukkan perilaku yang sama.
RBT
2
Beberapa analisis mengatakan querySelector membutuhkan waktu lebih lama daripada getElementById, seperti di sini dimlucas.com/index.php/2016/09/17/… . Bagaimana jika kita memperhitungkan waktu akses? Apakah simpul langsung yang diperoleh dari getElementById membutuhkan lebih banyak waktu daripada yang statis dari querySelector?
Eric
1
@RBT Saya sudah menyebutkan bahwa DOM API lama ini tidak mengembalikan objek NodeList, mereka mengembalikan HTMLCollections.
Miscreant
@ Eric document.getElementById()tidak mengembalikan simpul hidup. Ini lebih cepat daripada document.querySelector('#id_here')mungkin karena querySelectorharus mengurai pemilih CSS terlebih dahulu.
Miscreant
68

Untuk jawaban ini, saya lihat querySelectordan querySelectorAllsebagai querySelector * dan getElementById, getElementsByClassName, getElementsByTagName, dan getElementsByNamesebagai getElement *.

Perbedaan utama

  1. querySelector * lebih fleksibel, karena Anda dapat memberikannya pemilih CSS3 apa pun, bukan hanya yang sederhana untuk id, tag, atau kelas.
  2. Kinerja querySelector berubah dengan ukuran DOM yang digunakan. * Untuk lebih tepatnya, panggilan querySelector * dijalankan dalam waktu O (n) dan getElement * panggilan dijalankan dalam waktu O (1), di mana n adalah jumlah total semua anak dari elemen atau dokumen yang dipanggil. Fakta ini tampaknya yang paling tidak terkenal, jadi saya berani.
  3. panggilan getElement * mengembalikan referensi langsung ke DOM, sedangkan querySelector * secara internal membuat salinan dari elemen yang dipilih sebelum mengembalikan referensi kepada mereka. Ini disebut sebagai elemen "hidup" dan "statis". Ini TIDAK sepenuhnya terkait dengan jenis yang mereka kembalikan. Tidak ada cara saya tahu untuk mengetahui apakah suatu elemen hidup atau statis secara terprogram, karena tergantung pada apakah elemen itu disalin pada beberapa titik, dan bukan merupakan properti intrinsik dari data. Perubahan ke elemen langsung langsung diterapkan - mengubah elemen langsung mengubahnya langsung di DOM, dan oleh karena itu baris JS berikutnya dapat melihat perubahan itu, dan menyebar ke elemen langsung lainnya yang mereferensikan elemen tersebut dengan segera. Perubahan pada elemen statis hanya ditulis kembali ke DOM setelah skrip saat ini selesai dijalankan.
  4. Jenis pengembalian panggilan ini bervariasi. querySelectordan getElementByIdkeduanya mengembalikan elemen tunggal. querySelectorAlldan getElementsByNamekeduanya mengembalikan NodeLists, menjadi fungsi yang lebih baru yang ditambahkan setelah HTMLCollection keluar dari mode. Yang lebih tua getElementsByClassNamedan getElementsByTagNamekeduanya mengembalikan HTMLCollections. Sekali lagi, ini pada dasarnya tidak relevan dengan apakah unsur-unsurnya hidup atau statis.

Konsep-konsep ini dirangkum dalam tabel berikut.

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)

Detail, Tip, dan Contoh

  • HTMLCollections tidak seperti array seperti NodeLists dan tidak mendukung .forEach (). Saya menemukan operator spread berguna untuk mengatasi ini:

    [...document.getElementsByClassName("someClass")].forEach()

  • Setiap elemen, dan global document, memiliki akses ke semua fungsi ini kecuali untuk getElementByIddan getElementsByName, yang hanya diimplementasikan pada document.

  • Memanggil panggilan getElement * alih-alih menggunakan querySelector * akan meningkatkan kinerja, terutama pada DOM yang sangat besar. Bahkan pada DOM kecil dan / atau dengan rantai yang sangat panjang, umumnya lebih cepat. Namun, kecuali Anda tahu Anda membutuhkan kinerja, keterbacaan kueriSelektor * harus lebih disukai. querySelectorAllseringkali lebih sulit untuk ditulis ulang, karena Anda harus memilih elemen dari NodeList atau HTMLCollection di setiap langkah. Misalnya, kode berikut ini tidak berfungsi:

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`.
  • Karena semua elemen memiliki akses ke panggilan querySelector * dan getElement *, Anda dapat membuat rantai menggunakan kedua panggilan, yang dapat berguna jika Anda menginginkan beberapa peningkatan kinerja, tetapi tidak dapat menghindari querySelector yang tidak dapat ditulis dalam hal panggilan getElement * .

  • Meskipun umumnya mudah untuk mengetahui apakah pemilih dapat ditulis hanya menggunakan panggilan getElement *, ada satu kasus yang mungkin tidak jelas:

    document.querySelectorAll(".class1.class2")

    dapat ditulis ulang sebagai

    document.getElementsByClassName("class1 class2")

  • Menggunakan getElement * pada elemen statis yang diambil dengan querySelector * akan menghasilkan elemen yang hidup sehubungan dengan subset statis DOM yang disalin oleh querySelector, tetapi tidak hidup sehubungan dengan dokumen lengkap DOM ... ini adalah tempat sederhana interpretasi langsung / statis elemen mulai berantakan. Anda mungkin harus menghindari situasi di mana Anda harus khawatir tentang hal ini, tetapi jika Anda melakukannya, ingat bahwa querySelector * memanggil elemen copy yang mereka temukan sebelum mengembalikan referensi kepada mereka, tetapi panggilan getElement * mengambil referensi langsung tanpa menyalin.

  • Baik API menentukan elemen mana yang harus dipilih terlebih dahulu jika ada beberapa kecocokan.

  • Karena querySelector * berulang melalui DOM sampai menemukan kecocokan (lihat Perbedaan Utama # 2), hal di atas juga menyiratkan bahwa Anda tidak dapat mengandalkan posisi elemen yang Anda cari di DOM untuk memastikan bahwa itu ditemukan dengan cepat - the browser dapat beralih melalui DOM mundur, maju, mendalam pertama, luasnya pertama, atau sebaliknya. getElement * masih akan menemukan elemen dalam jumlah waktu yang kira-kira sama terlepas dari penempatannya.

Timofey 'Sasha' Kondrashov
sumber
4
Sejauh ini jawaban yang paling tepat tentang topik ini. Harus lebih ditingkatkan.
SeaWarrior404
sangat tepat harus dimasukkan ke dalam blog Anda, Sasha
theking2
25

Saya datang ke halaman ini murni untuk mengetahui metode yang lebih baik untuk digunakan dalam hal kinerja - yaitu yang lebih cepat:

querySelector / querySelectorAll or getElementsByClassName

dan saya menemukan ini: https://jsperf.com/getelementsbyclassname-vs-queryselectorall/18

Ini menjalankan tes pada 2 x contoh di atas, ditambah chuck dalam tes untuk pemilih setara jQuery juga. hasil tes saya adalah sebagai berikut:

getElementsByClassName = 1,138,018 operations / sec - <<< clear winner
querySelectorAll = 39,033 operations / sec
jquery select = 381,648 operations / sec
OTurner
sumber
1
Wow, itu perbedaan besar , terima kasih sudah melihatnya. Jelas querySelectorAllmembutuhkan kerja tambahan di belakang layar (termasuk parsing ekspresi pemilih, akuntansi untuk elemen semu, dll.), Sementara getElementsByClassNameitu hanyalah objek traversal rekursif.
John Weisz
18

querySelector bisa berupa CSS lengkap (3) -Pilih dengan ID dan Kelas dan Pseudo-Kelas bersama-sama seperti ini:

'#id.class:pseudo'

// or

'tag #id .class .class.class'

dengan getElementByClassNameAnda bisa mendefinisikan kelas

'class'

dengan getElementByIdAnda bisa mendefinisikan id

'id'
algoritme
sumber
1
Apakah :firstpemilih CSS, sekarang? :first-class, atau :first-of-typemungkin, tapi saya pikir :firstitu penambahan JavaScript / jQuery / Sizzle.
David mengatakan mengembalikan Monica
@ Davidvidomas Ya itu, itu adalah bagian dari CSS3. Ini dapat digunakan seperti ini: css-tricks.com/almanac/selectors/f/first-child
algorhythm
2
tetapi :first, jelas, tidak :first-child.
David mengatakan mengembalikan Monica
3
"Penulis disarankan bahwa sementara penggunaan elemen pseudo dalam penyeleksi diizinkan, mereka tidak akan cocok dengan elemen apa pun dalam dokumen, dan dengan demikian tidak akan menghasilkan elemen apa pun yang dikembalikan. Oleh karena itu, penulis disarankan untuk menghindari penggunaan pseudo- elemen dalam penyeleksi yang diteruskan ke metode yang ditentukan dalam spesifikasi ini. " w3.org/TR/selectors-api/#grammar
remer kaya
Juga, ada bug di IE (tentu saja) yang menyebabkannya mengembalikan elemen html root bukannya daftar elemen kosong ketika memilih elemen pseudo.
rich remer
7

querySelectordan querySelectorAllmerupakan API yang relatif baru, sedangkan getElementByIddan getElementsByClassNametelah bersama kami lebih lama. Itu berarti bahwa apa yang Anda gunakan sebagian besar akan bergantung pada browser yang Anda perlukan.

Adapun :, itu memiliki makna khusus sehingga Anda harus menghindarinya jika Anda harus menggunakannya sebagai bagian dari ID / nama kelas.

Jan Hančič
sumber
13
Ini belum tentu benar. Misalnya, querySelectorAlltersedia di IE8, sedangkan getElementsByClassNametidak.
DaveJ
querySelectorAll... pada dasarnya semua: caniuse.com/#search=querySelectorAll
dsdsdsdsd
1
@Naveen getelementsbyclassname vs querySelectorAll vs jquery select mungkin bisa membantu.
lowtechsun
5

querySelectoradalah dari w3c Selector API

getElementByadalah dari w3c DOM API

IMO perbedaan yang paling menonjol adalah bahwa tipe kembalinya querySelectorAlladalah daftar simpul statis dan untuk getElementsByitu adalah daftar simpul langsung. Karena itu perulangan di demo 2 tidak pernah berakhir karena lislive dan memperbarui sendiri selama setiap iterasi.

// Demo 1 correct
var ul = document.querySelectorAll('ul')[0],
    lis = ul.querySelectorAll("li");
for(var i = 0; i < lis.length ; i++){
    ul.appendChild(document.createElement("li"));
}

// Demo 2 wrong
var ul = document.getElementsByTagName('ul')[0], 
    lis = ul.getElementsByTagName("li"); 
for(var i = 0; i < lis.length ; i++){
    ul.appendChild(document.createElement("li")); 
}
mzoz
sumber
4

Perbedaan antara "querySelector" dan "querySelectorAll"

//querySelector returns single element
let listsingle = document.querySelector('li');
console.log(listsingle);


//querySelectorAll returns lit/array of elements
let list = document.querySelectorAll('li');
console.log(list);


//Note : output will be visible in Console
<ul>
<li class="test">ffff</li>
<li class="test">vvvv</li>
<li>dddd</li>
<li class="test">ddff</li>
</ul>

Ambuj Khanna
sumber
2

Lihat ini

https://codepen.io/bagdaulet/pen/bzdKjL

getElementById tercepat dari querySelector pada 25%

jquery paling lambat

var q = time_my_script(function() {

    for (i = 0; i < 1000000; i++) {
         var w = document.querySelector('#ll');
    }

});

console.log('querySelector: '+q+'ms');
Багдаулет Сайын
sumber
-3

Perbedaan utama antara querySelector dan getlementbyID (Claassname, Tagname dll) adalah jika ada lebih dari satu elemen yang memuaskan kondisi querySelector akan mengembalikan hanya satu output sedangkan getElementBy * akan mengembalikan semua elemen.

Mari kita pertimbangkan contoh untuk membuatnya lebih jelas.

 <nav id="primary" class="menu">
                            <a class="link" href="#">For Business</a>
                            <a class="link" href="#">Become an Instructor</a>
                            <a class="link" href="#">Mobile Applications</a>
                            <a class="link" href="#">Support</a>
                            <a class="link" href="#">Help</a>
   </nav> 

Kode di bawah ini akan menjelaskan perbedaannya

**QUERY SELECTOR**
document.querySelector('.link'); // Output : For Business (element)

document.querySelectorAll('.link'); //Out All the element with class link

**GET ELEMENT**
document.getElementsByClassName('link') // Output : will return all the element with a class "link" but whereas in query selector it will return only one element which encounters first.

Inshort jika kita ingin memilih elemen tunggal untuk queryslector atau jika kita ingin banyak elemen, getElement

ajay verma
sumber
1
getElementById mengembalikan hanya satu elemen, ini bukan perbedaan di antara keduanya.
Timofey 'Sasha' Kondrashov