Для цієї відповіді, я маю на увазі querySelectorі , querySelectorAllяк querySelector * і getElementById, getElementsByClassName, getElementsByTagName, і , getElementsByNameяк getElement *.
Основні відмінності
- querySelector * є більш гнучким, оскільки ви можете передати його будь-якому селектору CSS3, а не лише прості для ідентифікатора, тегу чи класу.
- Продуктивність querySelector змінюється залежно від розміру DOM, на який він викликається. * Якщо бути точним, querySelector * дзвінки виконуються в O (n) час і getElement * виклики виконуються в O (1) час, де n - загальна кількість всіх дітей елемента або документа, на який він викликається. Цей факт видається найменш відомим, тому я його підкреслюю.
- getElement * викликає повернення прямих посилань на DOM, тоді як querySelector * робить внутрішньо копії вибраних елементів перед поверненням посилань на них. Вони називаються "живими" та "статичними" елементами. Це НЕ суворо пов'язане з типами, які вони повертають. Я не можу мені сказати, чи є елемент живим або статичним програмним шляхом, оскільки це залежить від того, чи був елемент скопійований у якийсь момент, і чи не є властивим для цього властивістю даних. Зміни живих елементів застосовуються негайно - зміна живого елемента змінює його безпосередньо в DOM, і тому наступний рядок JS може побачити цю зміну, і він поширюється на будь-які інші живі елементи, що посилаються на цей елемент негайно. Зміни статичних елементів записуються до DOM лише після виконання поточного сценарію.
- Типи повернення цих дзвінків різняться.
querySelectorі getElementByIdобидва повертають один елемент. querySelectorAllі getElementsByNameобидва повертають NodeLists, будучи новішими функціями, доданими після того, як HTMLCollection вийшов з моди. Старші 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 * замість використання 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 *, ви можете робити ланцюги, використовуючи обидва виклики, що може бути корисно, якщо ви хочете певного підвищення продуктивності, але не можете уникнути запиту Selector, який не може бути записаний у викликах getElement * .
Хоча загалом легко сказати, чи можна записувати селектор, використовуючи лише виклики getElement *, є один випадок, який може бути не очевидним:
document.querySelectorAll(".class1.class2")
можна переписати як
document.getElementsByClassName("class1 class2")
Використання getElement * на статичному елементі, отриманому за допомогою querySelector *, призведе до отримання елемента, який знаходиться в реальному відношенні до статичного підмножини DOM, скопійованого querySelector, але не живе відносно повного документа DOM ... тут просто жива / статична інтерпретація елементів починає розвалюватися. Вам, мабуть, слід уникати ситуацій, коли вам доведеться турбуватися з цього приводу, але якщо це зробити, пам’ятайте, що querySelector * викликає копіюючі елементи, які вони знаходять, перш ніж повертати посилання на них, але getElement * викликає отримання прямих посилань без копіювання.
Жоден API не вказує, який елемент слід обрати спочатку, якщо є кілька збігів.
Оскільки querySelector * повторюється через DOM до тих пір, поки він не знайде збіг (див. Основну різницю №2), вищевикладене також означає, що ви не можете покластися на позицію елемента, який ви шукаєте в DOM, щоб гарантувати, що його буде знайдено швидко - браузер може повторювати DOM назад, вперед, по-перше, по глибині чи іншим чином. getElement * все одно знайде елементи приблизно за однаковий час, незалежно від місця їх розміщення.