Búsqueda en JavaScript: getElement*, querySelector*
Explora y domina el Modelo de Objetos del Documento (DOM) en JavaScript para crear aplicaciones web interactivas y dinámicas con getElement* y querySelector*.
Antes de poder cambiar, mover o leer cualquier cosa en una página, tienes que encontrar el elemento que deseas. Este es el primer paso de casi cualquier tarea con el DOM, y JavaScript te proporciona dos familias de herramientas para ello:
- Métodos heredados
getElement*—getElementById,getElementsByClassName,getElementsByTagName. Son rápidos y devuelven colecciones activas. - Métodos modernos
querySelector*—querySelector,querySelectorAll. Aceptan cualquier selector CSS y devuelven resultados estáticos.
Esta guía cubre ambas familias, los auxiliares matches, closest y contains para verificar y recorrer el árbol, y el error más importante: la diferencia entre una colección activa y una estática. Cada ejemplo es ejecutable, para que puedas ver el resultado de inmediato.
Una vez que encuentres un elemento, los pasos habituales son recorrer el DOM para acceder a sus vecinos y manipular el DOM para modificarlo. Para una introducción más suave, consulta seleccionar elementos del DOM.
Acceso eficiente a elementos: getElementById
El método getElementById es la forma más rápida y confiable de acceder a un solo elemento, porque se supone que un ID es único dentro de un documento y los navegadores indexan los IDs internamente. Devuelve el elemento coincidente, o null si no existe ningún elemento con ese ID — así que protégete contra null antes de usar el resultado. Ten en cuenta que pasas el ID sin prefijo, sin el # inicial (ese es solo para los selectores CSS). En el siguiente ejemplo, el "Default text" inicial se reemplaza de inmediato.
<!-- snippet: html-result -->
<!DOCTYPE html>
<html>
<head>
<title>getElementById Example</title>
</head>
<body>
<div id="main-content">Default text</div>
<script>
const element = document.getElementById('main-content');
element.innerHTML = "Modified text!"
</script>
</body>
</html>Acceso a múltiples elementos: getElementsByClassName y getElementsByTagName
Cuando seleccionas elementos por nombre de clase o nombre de etiqueta, obtienes un HTMLCollection. Esta es una colección activa: se actualiza automáticamente a medida que cambia el DOM. Es similar a un array — puedes leer elementos por índice (els[0]) y comprobar els.length — pero no es un array real, por lo que no tiene forEach, map ni filter. Para iterarla de forma segura, conviértela primero con Array.from(...) (o el operador de propagación [...els]).
Ejemplo con getElementsByClassName
Accede a varios elementos con la misma clase usando getElementsByClassName. En este ejemplo tenemos dos elementos div con el mismo nombre de clase. Modificamos ambos seleccionando esos elementos por su nombre de clase.
<!-- snippet: html-result -->
<!DOCTYPE html>
<html>
<head>
<title>getElementsByClassName Example</title>
</head>
<body>
<div class="info">First Info</div>
<div class="info">Second Info</div>
<script>
const infoElements = document.getElementsByClassName('info');
Array.from(infoElements).forEach(el => el.innerHTML = "MODIFIED!");
</script>
</body>
</html>Ejemplo con getElementsByTagName
Recupera elementos por su nombre de etiqueta con getElementsByTagName. Es completamente similar al anterior, pero esta vez seleccionamos por el nombre de etiqueta, no por el nombre de clase.
<!-- snippet: html-result -->
<!DOCTYPE html>
<html>
<head>
<title>getElementsByTagName Example</title>
</head>
<body>
<p>First Paragraph</p>
<p>Second Paragraph</p>
<script>
const paragraphs = document.getElementsByTagName('p');
Array.from(paragraphs).forEach(el => el.innerHTML = "MODIFIED!");
</script>
</body>
</html>Búsquedas flexibles con querySelector y querySelectorAll
Selección con querySelector
Usa querySelector para encontrar el primer elemento que coincida con un selector CSS. En este ejemplo, seleccionamos el primer elemento con la clase text que es hijo directo del elemento con el id main.
<!-- snippet: html-result -->
<!DOCTYPE html>
<html>
<head>
<title>QuerySelector Example</title>
</head>
<body>
<div id="main"><span class="text">This will be replaced</span></div>
<div id="other"><span class="text">This one doesn't change</span></div>
<script>
const spanInsideDiv = document.querySelector('#main > .text');
spanInsideDiv.innerHTML = "MODIFIED!";
</script>
</body>
</html>Recuperar múltiples elementos con querySelectorAll
querySelectorAll devuelve todos los elementos que coincidan con un selector CSS, como un NodeList estático. Convenientemente, un NodeList sí tiene un forEach integrado, por lo que puedes iterarlo directamente sin convertirlo a un array primero.
La palabra estático es importante: querySelectorAll toma una instantánea de las coincidencias en el momento en que lo llamas. Si agregas o eliminas elementos coincidentes después, esa instantánea no cambia. Esto es exactamente lo opuesto a la HTMLCollection activa que devuelven los métodos getElementsBy*.
<!-- snippet: html-result -->
<!DOCTYPE html>
<html>
<head>
<title>QuerySelectorAll Example</title>
</head>
<body>
<ul>
<li class="item">Item 1</li>
<li class="item">Item 2</li>
</ul>
<script>
const items = document.querySelectorAll('.item');
items.forEach(item => item.innerHTML = "MODIFIED!");
</script>
</body>
</html>Activo vs. estático: el problema con las colecciones
Esta es la trampa que atrapa a la mayoría de los principiantes. Una HTMLCollection activa refleja el estado actual del DOM en cada lectura, mientras que un NodeList estático está congelado en el momento de la selección. El siguiente fragmento muestra cómo ambos reaccionan ante un elemento recién agregado:
// Suppose the page has two <li class="item"> elements.
const live = document.getElementsByClassName('item'); // live HTMLCollection
const snapshot = document.querySelectorAll('.item'); // static NodeList
console.log(live.length); // 2
console.log(snapshot.length); // 2
// Now add a third matching element.
const li = document.createElement('li');
li.className = 'item';
document.querySelector('ul').appendChild(li);
console.log(live.length); // 3 — updated automatically
console.log(snapshot.length); // 2 — still the old snapshotPor qué importa: iterar sobre una colección activa mientras se eliminan elementos coincidentes es una fuente clásica de elementos omitidos, porque la colección se reduce bajo tus pies. Un NodeList estático de querySelectorAll es más seguro en ese caso, ya que la lista no cambiará durante el bucle.
Verificar y recorrer: matches, closest y contains
La búsqueda no solo consiste en encontrar elementos — a menudo tienes un elemento y necesitas hacerle una pregunta sobre él.
element.matches(selector)devuelvetruesi el elemento en sí coincide con el selector CSS. Ideal para la delegación de eventos.element.closest(selector)recorre el árbol hacia arriba desde el elemento (incluido él mismo) y devuelve el ancestro más cercano que coincida, onull.parent.contains(node)devuelvetruesinodees el propio padre o un descendiente de él.
<!-- snippet: html-result -->
<!DOCTYPE html>
<html>
<body>
<section class="card">
<button id="save" class="btn primary">Save</button>
</section>
<div id="out"></div>
<script>
const btn = document.getElementById('save');
const section = document.querySelector('.card');
const out = document.getElementById('out');
out.innerHTML =
'matches(".primary"): ' + btn.matches('.primary') + '<br>' +
'closest(".card") is section: ' + (btn.closest('.card') === section) + '<br>' +
'section.contains(btn): ' + section.contains(btn);
</script>
</body>
</html>¿Qué método debo usar?
- ¿Necesitas un elemento por ID? Usa
getElementById— es el más rápido y claro. - ¿Necesitas un selector CSS (descendientes, combinadores, atributos,
:not())? UsaquerySelector/querySelectorAll. - ¿Necesitas una lista activa que rastree los cambios en el DOM? Usa
getElementsByClassName/getElementsByTagName. - ¿Tienes un elemento y necesitas probar o subir por el árbol? Usa
matches,closestocontains.
Conclusión
Encontrar elementos es la base de todo script con el DOM. Usa getElementById para IDs individuales, querySelector* para la flexibilidad de los selectores CSS, y los métodos getElementsBy* cuando genuinamente necesites una colección activa — solo recuerda la diferencia entre activo y estático para que las colecciones no te sorprendan a mitad de un bucle. Desde aquí, continúa con recorrer el DOM y manipulación del DOM.