Для этого ответа, я имею в виду querySelectorи , querySelectorAllкак querySelector * и getElementById, getElementsByClassName, getElementsByTagName, и , getElementsByNameкак getElement *.
Основные отличия
- querySelector * является более гибким, так как вы можете передать ему любой селектор CSS3, а не только простые для id, тега или класса.
- Производительность 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 *, вы можете создавать цепочки, используя оба вызова, что может быть полезно, если вы хотите повысить производительность, но не можете избежать запроса querySelector, который нельзя записать в терминах вызовов getElement *. ,
Хотя, как правило, легко определить, можно ли писать селектор, используя только вызовы getElement *, есть один случай, который может быть неочевидным:
document.querySelectorAll(".class1.class2")
можно переписать как
document.getElementsByClassName("class1 class2")
Использование getElement * для статического элемента, извлеченного с помощью querySelector *, приведет к тому, что элемент будет действителен по отношению к статическому подмножеству DOM, скопированному с помощью querySelector, но не будет действителен по отношению к полному DOM документа ... вот где простое Живая / статическая интерпретация элементов начинает разваливаться. Вам, вероятно, следует избегать ситуаций, когда вам нужно беспокоиться об этом, но если вы это сделаете, помните, что querySelector * вызывает элементы копирования, которые они находят, прежде чем возвращать ссылки на них, но getElement * вызывает выборку прямых ссылок без копирования.
Ни один API не указывает, какой элемент должен быть выбран первым, если есть несколько совпадений.
Поскольку querySelector * выполняет итерацию по DOM до тех пор, пока не найдет совпадение (см. Основное отличие № 2), вышеприведенное также подразумевает, что вы не можете полагаться на положение элемента, который вы ищете в DOM, чтобы гарантировать его быстрое нахождение - Браузер может перебирать DOM назад, вперед, сначала в глубину, в ширину или другим способом. getElement * все равно будет находить элементы примерно в одинаковое время независимо от их размещения.