Cho câu trả lời này, tôi đề cập đến querySelector
và querySelectorAll
như querySelector * và getElementById
, getElementsByClassName
, getElementsByTagName
, và getElementsByName
như getElement *.
Sự khác biệt chính
- 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.
- 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ó.
- 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.
- Các loại trả lại của các cuộc gọi này khác nhau.
querySelector
và getElementById
cả hai trả về một phần tử duy nhất. querySelectorAll
và getElementsByName
cả 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 getElementsByClassName
và getElementsByTagName
cả 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ừ getElementById
và getElementsByName
, 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. querySelectorAll
thườ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.