querySelector và querySelector ALL vs getElementsByClassName và getEuityById trong JavaScript


165

Tôi muốn biết chính xác sự khác biệt giữa querySelectorquerySelectorAllchống lại getElementsByClassNamegetElementById?

Từ liên kết này, tôi có thể thu thập rằng querySelectortôi có thể viết document.querySelector(".myclass")để lấy các phần tử với lớp myclassdocument.querySelector("#myid")để lấy phần tử có ID myid. Nhưng tôi đã có thể làm điều đó getElementsByClassNamegetElementById. Cái nào nên được ưu tiên?

Ngoài ra tôi làm việc trong XPages nơi ID được tạo động bằng dấu hai chấm và trông như thế này view:_id1:inputText1. Vì vậy, khi tôi viết document.querySelector("#view:_id1:inputText1")nó không hoạt động. Nhưng viết document.getElementById("view:_id1:inputText1")tác phẩm. Bất cứ ý tưởng tại sao?


1
querySelector được sử dụng để truy vấn cây DOM DOM có thể bao gồm phần tử html và các thuộc tính của nó làm thành phần chính để truy vấn ... bạn có thể sử dụng biểu thức chính quy để đạt được điều này .. dojo.query () thực hiện điều tương tự
anix

1
Ý bạn là document.querySelectorAll(".myclass")sao? Sử dụng document.querySelector(".myclass")sẽ chỉ trả lại phần tử đầu tiên phù hợp.
mhatch

Câu trả lời:


113

Tôi muốn biết chính xác sự khác biệt giữa querySelector và querySelectorAll so với getElementsByClassName và getEuityById là gì?

Cú pháp và hỗ trợ trình duyệt.

querySelector sẽ hữu ích hơn khi bạn muốn sử dụng các bộ chọn phức tạp hơn.

ví dụ: Tất cả các mục danh sách xuất phát từ một thành phần là thành viên của lớp foo: .foo li

document.querySelector ("# view: _id1: inputText1") nó không hoạt động. Nhưng viết tài liệu.getEuityById ("view: _id1: inputText1") hoạt động. Bất cứ ý tưởng tại sao?

Các :nhân vật có ý nghĩa đặc biệt trong một bộ chọn. Bạn phải thoát khỏi nó. (Ký tự thoát của bộ chọn cũng có ý nghĩa đặc biệt trong chuỗi JS, vì vậy bạn cũng phải thoát ).

document.querySelector("#view\\:_id1\\:inputText1")

3
Nó sẽ thay đổi từ trình duyệt này sang trình duyệt khác (và từ phiên bản này sang phiên bản khác). Tôi cho rằng những cái dựa trên bộ chọn đắt hơn (nhưng không phải theo cách có thể sẽ có ý nghĩa)
Quentin

1
Tôi ủng hộ tuyên bố của @ janaspage. Trang web cũng bị sập ngày hôm nay.
doplumi

6
Và về lựa chọn lớp, xem thêm jsperf.com/getelementsbyclassname-vs-queryselectorall/25 . Kết luận: người ta nên thích javascript thuần túy hơn jquery, và các chức năng cụ thể getElementByIdgetElementsByClassName. Lựa chọn className có thể chậm hơn hàng trăm lần mà không có getElementsByClassName.
Atrahocation 16/2/2016

101

thu thập từ Tài liệu Mozilla:

Giao diện NodeSelector Đặc tả này thêm hai phương thức mới vào bất kỳ đối tượng nào thực hiện giao diện Document, DocumentFragment hoặc Element:

truy vấn

Trả về nút Phần tử phù hợp đầu tiên trong cây con của nút. Nếu không tìm thấy nút phù hợp, null được trả về.

querySelector ALL

Trả về một NodeList chứa tất cả các nút Phần tử phù hợp trong cây con của nút hoặc một NodeList trống nếu không tìm thấy kết quả khớp nào.

Lưu ý: NodeList được trả về bởi querySelectorAll()không tồn tại, điều đó có nghĩa là những thay đổi trong DOM không được phản ánh trong bộ sưu tập. Điều này khác với các phương thức truy vấn DOM khác trả về danh sách nút trực tiếp.


32
+1 để chỉ ra sự phân biệt danh sách nút trực tiếp. Đó là một sự khác biệt cực kỳ quan trọng cần biết tùy thuộc vào cách bạn định sử dụng kết quả.
jmbpiano ngày

7
"Live" có nghĩa là nút được thêm vào trong thời gian chạy DOM và có thể hoạt động trên nút được thêm newley đó
diEcho

83

Về sự khác biệt, có một điều quan trọng trong kết quả giữa querySelectorAllgetElementsByClassName: giá trị trả về là khác nhau. querySelectorAllsẽ trả về một bộ sưu tập tĩnh, trong khi getElementsByClassNametrả về một bộ sưu tập trực tiếp. Điều này có thể dẫn đến nhầm lẫn nếu bạn lưu trữ kết quả trong một biến để sử dụng sau:

  • Một biến được tạo với querySelectorAllsẽ chứa các phần tử đáp ứng bộ chọn tại thời điểm phương thức được gọi .
  • Một biến được tạo với getElementsByClassNamesẽ chứa các phần tử đáp ứng bộ chọn khi nó được sử dụng (có thể khác với thời điểm phương thức được gọi).

Ví dụ: lưu ý cách ngay cả khi bạn chưa gán lại các biến aux1aux2chúng chứa các giá trị khác nhau sau khi cập nhật các lớp:

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


2
Chỉ cần đề cập - Tất cả các apis DOM cũ hơn trả về một danh sách nút cụ thể document.getElementsByName, document.getElementsByTagNameNShoặc document.getElementsByTagNamesẽ thể hiện hành vi tương tự.
RBT

2
Một số phân tích nói rằng querySelector mất nhiều thời gian hơn getEuityById , như ở đây dimlucas.com/index.php/2016/09/17/ . Điều gì xảy ra nếu chúng ta dành thời gian truy cập vào tài khoản? Nút trực tiếp thu được từ getEuityById có mất nhiều thời gian hơn nút tĩnh từ querySelector không?
Eric

1
@RBT Tôi muốn đề cập rằng các API DOM cũ hơn này không trả về các đối tượng NodeList, chúng trả về HTMLCollections.
Linh tinh

@Eric document.getElementById()không trả về một nút trực tiếp. Nó nhanh hơn document.querySelector('#id_here')có lẽ vì querySelectorsẽ phải phân tích bộ chọn CSS trước.
Linh tinh

68

Cho câu trả lời này, tôi đề cập đến querySelectorquerySelectorAllnhư querySelector * và getElementById, getElementsByClassName, getElementsByTagName, và getElementsByNamenhư getElement *.

Sự khác biệt chính

  1. querySelector * linh hoạt hơn, vì bạn có thể vượt qua nó bất kỳ bộ chọn CSS3 nào, không chỉ các bộ chọn đơn giản cho id, thẻ hoặc lớp.
  2. Hiệu năng của querySelector thay đổi theo kích thước của DOM mà nó được gọi. * Để chính xác, các cuộc gọi querySelector * chạy trong thời gian O (n) và getEuity * chạy trong thời gian O (1), trong đó n là tổng số tất cả con của phần tử hoặc tài liệu mà nó được gọi. Thực tế này có vẻ là ít được biết đến nhất, vì vậy tôi đang nói về nó.
  3. getEuity * gọi trả về các tham chiếu trực tiếp đến DOM, trong khi querySelector * tạo nội bộ các bản sao của các phần tử được chọn trước khi trả lại các tham chiếu cho chúng. Chúng được gọi là các yếu tố "sống" và "tĩnh". Điều này KHÔNG liên quan chặt chẽ đến các loại mà họ trả lại. Không có cách nào tôi biết để biết liệu một phần tử đang sống hay tĩnh theo chương trình, vì nó phụ thuộc vào việc phần tử được sao chép tại một thời điểm nào đó và không phải là một thuộc tính nội tại của dữ liệu. Thay đổi thành phần tử trực tiếp áp dụng ngay lập tức - thay đổi phần tử trực tiếp sẽ thay đổi phần tử trực tiếp trong DOM và do đó, dòng tiếp theo của JS có thể thấy sự thay đổi đó và nó lan truyền đến bất kỳ phần tử sống nào khác tham chiếu phần tử đó ngay lập tức. Thay đổi thành phần tĩnh chỉ được ghi lại vào DOM sau khi tập lệnh hiện tại được thực thi.
  4. Các loại trả lại của các cuộc gọi này khác nhau. querySelectorgetElementByIdcả hai trả về một phần tử duy nhất. querySelectorAllgetElementsByNamecả hai trả về NodeLists, là các hàm mới hơn được thêm vào sau khi HTMLCollection không còn hợp thời. Các HTMLCollections cũ hơn getElementsByClassNamegetElementsByTagNamecả hai trả về. Một lần nữa, điều này về cơ bản không liên quan đến việc các yếu tố là sống hay tĩnh.

Những khái niệm này được tóm tắt trong bảng sau.

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)

Chi tiết, Mẹo và Ví dụ

  • HTMLCollections không giống như mảng NodeLists và không hỗ trợ .forEach (). Tôi thấy toán tử lây lan hữu ích để giải quyết vấn đề này:

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

  • Mọi yếu tố và toàn cầu documentđều có quyền truy cập vào tất cả các chức năng này ngoại trừ getElementByIdgetElementsByName, chỉ được thực hiện trên đó document.

  • Xâu chuỗi các cuộc gọi getEuity * thay vì sử dụng querySelector * sẽ cải thiện hiệu suất, đặc biệt là trên các DOM rất lớn. Ngay cả trên các DOM nhỏ và / hoặc với các chuỗi rất dài, nó thường nhanh hơn. Tuy nhiên, trừ khi bạn biết bạn cần hiệu năng, tính dễ đọc của querySelector * nên được ưu tiên. querySelectorAllthường khó viết lại hơn, bởi vì bạn phải chọn các phần tử từ NodeList hoặc HTMLCollection ở mỗi bước. Ví dụ: đoạn mã sau không hoạt động:

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`.
  • Vì tất cả các thành phần đều có quyền truy cập vào cả các lệnh gọi querySelector * và getEuity *, bạn có thể tạo chuỗi bằng cả hai cuộc gọi, điều này có thể hữu ích nếu bạn muốn tăng hiệu suất, nhưng không thể tránh truy vấnSelector không thể được viết theo các cuộc gọi getEuity * .

  • Mặc dù nói chung rất dễ để biết liệu bộ chọn có thể được viết chỉ bằng các lệnh gọi getEuity * hay không, có một trường hợp có thể không rõ ràng:

    document.querySelectorAll(".class1.class2")

    có thể được viết lại như

    document.getElementsByClassName("class1 class2")

  • Sử dụng getEuity * trên một phần tử tĩnh được tìm nạp bằng querySelector * sẽ dẫn đến một phần tử sống đối với tập hợp con tĩnh của DOM được sao chép bởi querySelector, nhưng không tương ứng với DOM tài liệu đầy đủ ... đây là nơi đơn giản giải thích trực tiếp / tĩnh của các yếu tố bắt đầu sụp đổ. Bạn có thể nên tránh các tình huống phải lo lắng về vấn đề này, nhưng nếu có, hãy nhớ rằng querySelector * gọi các phần tử sao chép mà chúng tìm thấy trước khi trả lại các tham chiếu cho chúng, nhưng getEuity * gọi các tham chiếu trực tiếp mà không cần sao chép.

  • API không chỉ định phần tử nào sẽ được chọn trước nếu có nhiều kết quả khớp.

  • Vì querySelector * lặp qua DOM cho đến khi tìm thấy kết quả khớp (xem Sự khác biệt chính # 2), ở trên cũng ngụ ý rằng bạn không thể dựa vào vị trí của một yếu tố bạn đang tìm kiếm trong DOM để đảm bảo rằng nó được tìm thấy nhanh chóng - trình duyệt có thể lặp qua DOM ngược, tiến, sâu trước, rộng trước hoặc nếu không. getEuity * vẫn sẽ tìm thấy các phần tử trong cùng một khoảng thời gian bất kể vị trí của chúng.


4
Cho đến nay câu trả lời chính xác nhất về chủ đề này. Nên nâng cao hơn nữa.
SeaWar Warrior404

rất chính xác nên được đưa vào blog của bạn, Sasha
theking2

25

Tôi đến trang này hoàn toàn để tìm ra phương pháp tốt hơn để sử dụng về mặt hiệu suất - tức là nhanh hơn:

querySelector / querySelectorAll or getElementsByClassName

và tôi đã tìm thấy điều này: https://jsperf.com/getelementsbyclassname-vs-queryselectorall/18

Nó chạy thử nghiệm trên 2 ví dụ ở trên, cộng với thử nghiệm trong bộ kiểm tra cho bộ chọn tương đương của jQuery. kết quả kiểm tra của tôi như sau:

getElementsByClassName = 1,138,018 operations / sec - <<< clear winner
querySelectorAll = 39,033 operations / sec
jquery select = 381,648 operations / sec

1
Wow, đó là một sự khác biệt lớn , cảm ơn vì đã tìm kiếm nó. Rõ ràng querySelectorAllcần có công việc bổ sung đằng sau hậu trường (bao gồm phân tích biểu thức bộ chọn, tính toán các phần tử giả, v.v.), trong khi getElementsByClassNamechỉ đơn thuần là một đối tượng đệ quy.
John Weisz

18

querySelector có thể là một CSS (3) -Selector hoàn chỉnh với ID và Class và Pseudo-Class cùng nhau như thế này:

'#id.class:pseudo'

// or

'tag #id .class .class.class'

với getElementByClassNamebạn chỉ có thể định nghĩa một lớp

'class'

với getElementByIdbạn chỉ có thể xác định một id

'id'

1
:firstmột bộ chọn CSS, bây giờ? :first-class, hoặc :first-of-typecó thể, nhưng tôi nghĩ :firstlà một bổ sung JavaScript / jQuery / Sizzle.
David nói phục hồi Monica

@DavidThomas Đúng vậy, nó là một phần của CSS3. Nó có thể được sử dụng như thế này: css-tricks.com/almanac/selector/f/first-child
algorardi 15/1/2015

2
nhưng :firstlà, đáng chú ý, không :first-child.
David nói phục hồi Monica

3
"Các tác giả được khuyến cáo rằng mặc dù việc sử dụng các yếu tố giả trong bộ chọn được cho phép, nhưng chúng sẽ không khớp với bất kỳ yếu tố nào trong tài liệu và do đó sẽ không dẫn đến bất kỳ yếu tố nào được trả về. Do đó, các tác giả nên tránh sử dụng giả các phần tử trong bộ chọn được truyền cho các phương thức được xác định trong thông số kỹ thuật này. " w3.org/TR/selector-api/#grammar
người làm giàu giàu có

Ngoài ra, có một lỗi trong IE (tất nhiên) khiến nó trả về phần tử html gốc thay vì danh sách phần tử trống khi chọn phần tử giả.
người làm giàu giàu có

7

querySelectorquerySelectorAlllà một API tương đối mới, trong khi đó getElementByIdgetElementsByClassNameđã ở với chúng tôi lâu hơn rất nhiều. Điều đó có nghĩa là những gì bạn sử dụng sẽ chủ yếu phụ thuộc vào trình duyệt nào bạn cần hỗ trợ.

Đối với :, nó có một ý nghĩa đặc biệt vì vậy bạn phải thoát nó nếu bạn phải sử dụng nó như một phần của tên ID / lớp.


13
Điều này không thực sự đúng. Ví dụ, querySelectorAllcó sẵn trong IE8, trong khi getElementsByClassNamekhông.
DaveJ

querySelectorAll... về cơ bản là tất cả mọi thứ: caniuse.com/#search=querySelector
ALL


5

querySelectorlà của API chọn w3c

getElementBylà của API DOM w3c

IMO sự khác biệt đáng chú ý nhất là kiểu trả về querySelectorAlllà danh sách nút tĩnh và đối với getElementsBydanh sách nút trực tiếp. Do đó, vòng lặp trong bản demo 2 không bao giờ kết thúc vì lisđang hoạt động và tự cập nhật trong mỗi lần lặp.

// 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")); 
}

4

Sự khác biệt giữa "querySelector" và "querySelector ALL"

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


2

nhìn này

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

getEuityById nhanh hơn querySelector trên 25%

jquery là chậm nhất

var q = time_my_script(function() {

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

});

console.log('querySelector: '+q+'ms');

-3

Sự khác biệt chính giữa querySelector và getuitybyID (Claassname, Tagname, v.v.) là nếu có nhiều hơn một phần tử làm bão hòa điều kiện querySelector sẽ chỉ trả về một đầu ra trong khi getEuityBy * sẽ trả về tất cả các phần tử.

Hãy xem xét một ví dụ để làm cho nó rõ ràng hơn.

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

Mã dưới đây sẽ giải thích sự khác biệt

**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 nếu chúng ta muốn chọn một phần tử, hãy truy vấn hoặc nếu chúng ta muốn nhiều phần tử, hãy tìm getEuity


1
getEuityById chỉ trả về một yếu tố, đây không phải là một sự khác biệt giữa hai yếu tố này.
Timofey 'Sasha' Kondrashov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.