querySelector and querySelectorAll vs getElementsByClassName та getElementById в JavaScript


165

Я хотів би знати , що саме різниця між querySelectorі querySelectorAllпроти getElementsByClassNameі getElementById?

З цього посилання я querySelectorможу document.querySelector(".myclass")зрозуміти, що за допомогою я можу писати, щоб отримати елементи з класом myclassта document.querySelector("#myid")отримати елемент з ідентифікатором myid. Але я вже можу це зробити getElementsByClassNameі getElementById. Якому слід віддати перевагу?

Також я працюю в XPages, де ідентифікатор динамічно генерується двокрапкою і виглядає приблизно так view:_id1:inputText1. Тож коли я пишу, document.querySelector("#view:_id1:inputText1")це не працює. Але написання document.getElementById("view:_id1:inputText1")творів. Будь-які ідеї чому?


1
querySelector використовується для запиту дерева HTML DOM, який може включати html-елемент та його атрибути як ключові елементи для запиту ... ви можете використовувати регулярне вираження для досягнення цього .. dojo.query () робить те ж саме
anix

1
Ви не маєте на увазі document.querySelectorAll(".myclass")? Використання document.querySelector(".myclass")поверне лише перший елемент, який відповідає.
матч

Відповіді:


113

Мені хотілося б знати, у чому саме різниця між querySelector і querySelectorAll проти getElementsByClassName та getElementById?

Синтаксис та підтримка браузера.

querySelector корисніше, коли потрібно використовувати більш складні селектори.

наприклад, Усі елементи списку, походження від елемента, що належить до класу foo: .foo li

document.querySelector ("# view: _id1: inputText1") він не працює. Але запис document.getElementById ("view: _id1: inputText1") працює. Будь-які ідеї чому?

:Символ має особливе значення всередині селектора. Ви повинні уникнути цього. (Символ втечі селектора також має особливе значення в рядку JS, тому вам також потрібно уникнути цього ).

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

3
Він буде відрізнятися від браузера до браузера (і від версії до версії). Я б припустив, що селекціонери були дорожчими (але не таким чином, який коли-небудь буде значущим)
Квентін

1
Я підтримую заяву @ janaspage. Сайт також сьогодні не працює.
doplumi

6
А про вибір класу див. Також jsperf.com/getelementsbyclassname-vs-queryselectorall/25 . Висновок: слід набагато більше віддавати перевагу чистому JavaScript, ніж jquery, а конкретним функціям getElementByIdта getElementsByClassName. Вибір className може бути в декілька сотень разів повільнішим getElementsByClassName.
Атрахасіс

101

збирання з документації Mozilla:

Інтерфейс NodeSelector Ця специфікація додає два нові методи до будь-яких об'єктів, що реалізують інтерфейси Document, DocumentFragment або Element:

querySelector

Повертає перший узгоджений вузол Елемента в піддереві. Якщо не знайдено відповідний вузол, нуль повертається.

querySelectorAll

Повертає NodeList, що містить усі відповідні вузли Елементу в піддереві вузла, або порожній NodeList, якщо не знайдено збігів.

і

Примітка. Повернений NodeList querySelectorAll()- не в прямому ефірі, а це означає, що зміни в DOM не відображаються в колекції. Це відрізняється від інших методів запиту DOM, які повертають живі списки вузлів.


32
+1 для вказівки на відмінність списку живих вузлів. Це надзвичайно важлива різниця, яку слід знати, залежно від того, як ви збираєтесь використовувати результати.
jmbpiano

7
"live" означає вузол, доданий у час виконання DOM і може працювати над цим вузлом, який додав
Newley

83

Про відмінності, є важливий в результатах між querySelectorAllі getElementsByClassName: повертається значенням відрізняється. querySelectorAllповерне статичну колекцію, тоді як getElementsByClassNameповерне живу колекцію. Це може призвести до плутанини, якщо ви збережете результати у змінній для подальшого використання:

  • Змінна, згенерована з, querySelectorAllбуде містити елементи, які виконали селектор на той момент, коли метод викликався .
  • Змінна, сформована з getElementsByClassName, міститиме елементи, які виконали селектор при його використанні (що може відрізнятися від моменту виклику методу).

Наприклад, зауважте, як навіть якщо ви не переназначили змінні, aux1і aux2вони містять різні значення після оновлення класів:

// 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
Зауважимо лише, що всі старіші DOM apis повертають список вузлів, а саме document.getElementsByName, document.getElementsByTagNameNSабо document.getElementsByTagNameматимуть таку ж поведінку.
RBT

2
Деякі аналізи говорять querySelector займає більше часу , ніж getElementById, як тут dimlucas.com/index.php/2016/09/17 / ... . Що робити, якщо врахувати час доступу? Чи потрібен живий вузол, отриманий від getElementById, більше часу, ніж статичний з querySelector?
Ерік

1
@RBT Хочу зазначити, що ці старі API DOM не повертають об'єкти NodeList, вони повертають HTMLCollections.
Зловмисник

@Eric document.getElementById()не повертає живий вузол. Це швидше, ніж, document.querySelector('#id_here')мабуть, тому querySelector, що доведеться спочатку проаналізувати селектор CSS.
Проклятий

68

Для цієї відповіді, я маю на увазі querySelectorі , querySelectorAllяк querySelector * і getElementById, getElementsByClassName, getElementsByTagName, і , getElementsByNameяк getElement *.

Основні відмінності

  1. querySelector * є більш гнучким, оскільки ви можете передати його будь-якому селектору CSS3, а не лише прості для ідентифікатора, тегу чи класу.
  2. Продуктивність querySelector змінюється залежно від розміру DOM, на який він викликається. * Якщо бути точним, querySelector * дзвінки виконуються в O (n) час і getElement * виклики виконуються в O (1) час, де n - загальна кількість всіх дітей елемента або документа, на який він викликається. Цей факт видається найменш відомим, тому я його підкреслюю.
  3. getElement * викликає повернення прямих посилань на DOM, тоді як querySelector * робить внутрішньо копії вибраних елементів перед поверненням посилань на них. Вони називаються "живими" та "статичними" елементами. Це НЕ суворо пов'язане з типами, які вони повертають. Я не можу мені сказати, чи є елемент живим або статичним програмним шляхом, оскільки це залежить від того, чи був елемент скопійований у якийсь момент, і чи не є властивим для цього властивістю даних. Зміни живих елементів застосовуються негайно - зміна живого елемента змінює його безпосередньо в DOM, і тому наступний рядок JS може побачити цю зміну, і він поширюється на будь-які інші живі елементи, що посилаються на цей елемент негайно. Зміни статичних елементів записуються до DOM лише після виконання поточного сценарію.
  4. Типи повернення цих дзвінків різняться. 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 * все одно знайде елементи приблизно за однаковий час, незалежно від місця їх розміщення.


4
На сьогодні найточніша відповідь на цю тему. Слід більше заохочувати.
SeaWarrior404

Дуже точно слід розмістити у своєму блозі, Саша
theking2

25

Я зайшов на цю сторінку лише для того, щоб з’ясувати кращий метод використання з точки зору продуктивності - тобто який швидший:

querySelector / querySelectorAll or getElementsByClassName

і я виявив це: https://jsperf.com/getelementsbyclassname-vs-queryselectorall/18

Він проводить тест на 2-х прикладах, наведених вище, плюс додає також тест на еквівалентний селектор jQuery. мої результати тесту були такими:

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

1
Нічого, це величезна різниця, дякую, що подивився. Очевидно, що querySelectorAllпотрібна додаткова робота за лаштунками (включаючи розбір виразу селектора, облік псевдоелементів тощо), хоча getElementsByClassNameце лише рекурсивна обробка об'єкта.
Джон Вайс

18

querySelector може бути повним CSS (3) -електором з ідентифікаторами та класами та псевдокласами разом:

'#id.class:pseudo'

// or

'tag #id .class .class.class'

з getElementByClassNameви можете просто визначити клас

'class'

з getElementByIdви можете просто визначити ідентифікатор

'id'

1
Є чи :firstселектор CSS, тепер? :first-classабо, :first-of-typeможливо, але я подумав, що :firstце додаток JavaScript / jQuery / Sizzle.
Девід каже повернути Моніку

@DavidThomas Так, це частина CSS3. Це можна використовувати так: css-tricks.com/almanac/selectors/f/first-child
алгоритм

2
але :first, помітно, ні :first-child.
Девід каже повернути Моніку

3
"Автори рекомендують, що хоча використання псевдоелементів у селекторах дозволено, вони не будуть відповідати жодним елементам у документі і, таким чином, не призводять до повернення будь-яких елементів. Тому авторам рекомендується уникати використання псевдо- елементи у селекторах, які передаються методам, визначеним у цій специфікації. " w3.org/TR/selectors-api/#grammar
багатий ремер

Крім того, є помилка в IE (звичайно), яка змушує її повертати кореневий html-елемент замість порожнього списку елементів при виборі псевдоелементів.
багатий ремер

7

querySelectorі querySelectorAllє відносно новим API, тоді як getElementByIdі getElementsByClassNameз нами вже багато часу. Це означає, що те, що ви використовуєте, в основному залежатиме від того, які браузери вам потрібно підтримувати.

Що стосується :, це має особливе значення, тому вам доведеться уникати цього, якщо вам доведеться використовувати його як частину імені ID / класу.


13
Це не обов'язково правда. Наприклад, querySelectorAllдоступний в IE8, тоді getElementsByClassNameяк ні.
DaveJ

querySelectorAll... в основному все: caniuse.com/#search=querySelectorAll
dsdsdsdsd

1
@Naveen getelementsbyclassname vs querySelectorAll vs jquery select може бути корисним.
lowtechsun

5

querySelectorAPI w3c Selector

getElementByDOM API w3c

Найбільш помітною відмінністю IMO є те, що тип повернення querySelectorAll- це статичний список вузлів, а для getElementsByнього - список живих вузлів. Тому циклічне завершення в демо-версії 2 ніколи не закінчується, оскільки lisвоно живе і оновлюється під час кожної ітерації.

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

Різниця між "querySelector" і "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>


2

подивись на це

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

getElementById швидше, ніж querySelector на 25%

jquery найповільніший

var q = time_my_script(function() {

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

});

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

-3

Основна відмінність querySelector від getlementbyID (Claassname, Tagname тощо) полягає в тому, що є більше ніж один елемент, який задовольняє умові querySelector поверне лише один вихід, тоді як getElementBy * поверне всі елементи.

Розглянемо приклад, щоб зробити це більш зрозумілим.

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

Нижче код пояснить різницю

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

Якщо ви хочете вибрати один елемент, перейдіть для queryslector, або, якщо ми хочемо, щоб декілька елементів перейшли для getElement


1
getElementById повертає лише один елемент, це зовсім не різниця між двома.
Тимофей «Саша» Кондрашов
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.