Todo en una página es un árbol
El navegador no ve tu HTML como texto: lo convierte en una estructura de nodos conectados entre sí, el DOM, que JavaScript puede leer y modificar. Entender esa estructura es el primer paso para todo lo que sigue.
🧠 Todo es un árbol
Cuando el navegador carga una página, la convierte en una estructura de nodos llamada DOM (Document Object Model). Cada etiqueta se transforma en un objeto con el que JavaScript puede hablar: leerlo, cambiarlo, borrarlo o crear otros nuevos.
Esa estructura tiene forma de árbol genealógico: hay un nodo raíz (<html>), que tiene hijos (<head> y <body>), esos hijos tienen sus propios hijos, y así sucesivamente.
Todos estos nodos son accesibles desde JavaScript a través de un objeto global: en una página real, ese objeto es document (por ejemplo, document.body es el nodo que representa la etiqueta <body>). En los simuladores de este recurso vas a usar contenedor en lugar de document — es la misma idea, pero apuntando solo a tu casilla de práctica, no a toda la página.
Además, cuando el navegador convierte una etiqueta en nodo, en realidad genera dos tipos distintos: un nodo Elemento (la etiqueta en sí) y, adentro de él, un nodo Texto (el texto que esa etiqueta encierra).
<p>Esta página es <strong>muy sencilla</strong></p> se convierte en:
• nodo Elemento
<p>
↳ nodo Texto: "Esta página es"
↳ nodo Elemento
<strong>
↳ nodo Texto: "muy sencilla"
🧩 Pruébalo tú: nodo Elemento vs nodo Texto
Con el mismo ejemplo (<p>Esta página es <strong>muy sencilla</strong></p>), selecciona el nodo Elemento <p> y el nodo Elemento <strong>, e imprime con console.log el tagName de cada uno y el textContent del nodo Texto que tiene adentro <strong>.
🧩 Padres, hijos y hermanos
Un nodo puede tener un padre (el que lo contiene directamente), varios hijos (los que están directamente dentro de él) y hermanos (nodos que comparten el mismo padre).
Estas palabras no son solo vocabulario: JavaScript tiene propiedades que usan exactamente estos nombres, como elemento.parentElement y elemento.children, que vas a usar todo el tiempo para moverte por la página.
🧩 ¿Lo entendiste? · Repaso rápido
🗂️ Tipos de nodo y el objeto document
No todos los nodos del árbol son iguales: el navegador clasifica cada uno en un tipo distinto, según lo que representa. El punto de entrada a todo el árbol es un nodo especial de tipo Document: en una página real es el objeto document, y desde ahí accedes a todo lo demás (document.head, document.body).
| Tipo de nodo | Qué representa | Ejemplo |
|---|---|---|
| Document | El documento completo: la raíz desde la que se accede a todo | document |
| Element | Una etiqueta HTML | <div>, <p>, <strong> |
| Attr | Un atributo de una etiqueta | id="app", class="paises" |
| Text | El texto encerrado dentro de una etiqueta | "Hola Mundo" |
| Comment | Un comentario escrito en el HTML | <!-- nota --> |
Para explorar cualquiera de estos nodos, el navegador ofrece console.dir(): a diferencia de console.log(), muestra el nodo como un objeto navegable, con todas sus propiedades para abrir una por una en la consola.
console.dir(document); // el documento completo console.dir(document.head); // la sección <head> console.dir(document.body); // la sección <body>
console.dir(document.body) y presiona Enter.Elegir elementos con selectores CSS
Un problema clásico: tienes una lista de frutas en pantalla y quieres mostrar el nombre de la primera, o armaste una pequeña encuesta con checkboxes y necesitas contar cuántas personas marcaron "sí". Para hacer cualquiera de las dos cosas, antes que nada el programa necesita encontrar esos elementos dentro de la página — del mismo modo en que tú los encontrarías con la vista. querySelector y querySelectorAll son las herramientas para eso, usando los mismos selectores que ya conoces de CSS.
🔑 getElementById y los métodos clásicos
Antes de que existiera querySelector, la clase Document ya tenía formas de encontrar elementos. Son más viejas y menos flexibles, pero las vas a seguir viendo todo el tiempo en código ajeno, así que conviene reconocerlas.
HTML de referencia
<div id="app"> <p id="parrafo1">Hola Mundo</p> </div>
JavaScript
let div = document.getElementById("app");
let parrafo = document.getElementById("parrafo1");
console.log(div.innerHTML);
console.log(parrafo.innerHTML);
| Método | Qué devuelve | Ejemplo |
|---|---|---|
getElementById("id") | Un único elemento, el que tenga ese id (sin el #) | document.getElementById("parrafo1") |
getElementsByClassName("clase") | Todos los que tengan esa clase, como un Array de elementos | document.getElementsByClassName("paises") |
getElementsByTagName("etiqueta") | Todos los que tengan esa etiqueta — la menos específica, porque las etiquetas se repiten mucho | document.getElementsByTagName("div") |
Estos tres métodos siempre devuelven lo mismo que pidas en singular o en grupo: getElementById te da un solo elemento, los otros dos te dan un grupo recorrible con for...of (igual que harías con un Array). Mira paso a paso cómo se arma:
🧩 ¿Lo entendiste? · Practica
Usa contenedor.getElementById('fruta1') para encontrar la primera fruta, y contenedor.getElementsByClassName('fruta-clasica') para contar cuántas hay en total.
🔎 querySelector y querySelectorAll
Para resolver el problema de la lista de frutas, primero hay que decirle a JavaScript cuál elemento (o elementos) queremos tocar. Eso es justamente lo que hacen estos dos métodos — buscan, no modifican todavía nada.
A diferencia de getElementById/getElementsByClassName/getElementsByTagName que acabas de ver, querySelector acepta cualquier selector de CSS (id, clase, etiqueta, combinaciones, pseudo-clases) con una única sintaxis — por eso es la forma más usada hoy en día.
const primero = document.querySelector('.fruta');
const todas = document.querySelectorAll('.fruta');
// todas es recorrible con forEach
todas.forEach(function (el) {
console.log(el.textContent);
});
| Método | Qué devuelve | Ejemplo |
|---|---|---|
querySelector("sel") | El primer elemento que coincide con el selector (o null si no hay ninguno) | document.querySelector('.fruta') |
querySelectorAll("sel") | Todos los que coinciden, en una lista recorrible con forEach | document.querySelectorAll('.fruta') |
🧩 ¿Lo entendiste? · Completa el código
Completa con el método correcto en cada espacio.
document.('#resultado');
document.('.fruta');
✅ La pseudo-clase :checked
Ahora el problema de la encuesta: necesitas contar solo los checkboxes que la persona marcó, no todos los que existen en la página. Para eso, los selectores CSS incluyen pseudo-clases, como :checked, que filtra por un estado del elemento en este momento (marcado o no).
Mira primero, paso a paso, cómo se resuelve el problema completo (nombre de la primera fruta + cantidad marcada). Después te toca practicarlo tú en la pestaña siguiente.
| Selector | Qué selecciona |
|---|---|
.gusta | Todos los checkboxes con clase "gusta", estén marcados o no |
.gusta:checked | Solo los que están marcados en este momento |
✍️ Ahora practica tú
Es el mismo problema que acabas de ver resuelto paso a paso. Ahora te toca escribirlo tú: usa querySelector para el nombre de la fruta, y querySelectorAll('.gusta:checked') para contar los marcados.
Leer, escribir y decorar contenido
Otro problema clásico: corregir una actividad y avisarle a la persona si acertó, mostrando un mensaje ("¡Correcto!" o "Intenta de nuevo") pintado de verde o de rojo según el resultado. Ya sabes encontrar el elemento; ahora falta poder cambiar su contenido (textContent, innerHTML) y cambiar su apariencia con clases (classList).
📝 textContent vs innerHTML
Para avisarle a la persona si acertó, hay que escribir un mensaje dentro de un elemento que ya existe. Estas son las dos formas de hacerlo:
innerHTML viene de otra persona (algo que escribió un usuario) y no lo revisaste, podría meter una etiqueta <script> peligrosa. Regla: texto plano → textContent; HTML que tú controlas → innerHTML.Mira la diferencia con un mensaje de corrección más real, con varias etiquetas adentro — no solo una palabra en negrita:
| Propiedad | Qué hace | Ejemplo |
|---|---|---|
textContent | Lee o escribe texto plano. Si le asignas etiquetas HTML, NO se interpretan: aparecen tal cual | elemento.textContent = "¡Correcto!" |
innerHTML | Lee o escribe interpretando el HTML real | elemento.innerHTML = "<strong>Correcto</strong>" |
🧩 ¿Lo entendiste? · Practica
🎨 classList: add y remove
Ya tienes el mensaje escrito. Para pintarlo de verde o de rojo, no le cambias el color directamente: le agregas o sacas una clase CSS, y es el CSS el que define cómo se ve esa clase. Cada elemento tiene una propiedad classList para manejar sus clases.
Esta es la técnica central para dar feedback visual — exactamente lo que vas a usar para corregir actividades en el Recurso 2.
| Método | Qué hace | Ejemplo |
|---|---|---|
add("clase") | Agrega la clase si no la tiene | caja.classList.add('correcto') |
remove("clase") | Quita la clase si la tiene | caja.classList.remove('incorrecto') |
toggle("clase") | La agrega si no está, la saca si está | caja.classList.toggle('activa') |
contains("clase") | Devuelve true o false según si la tiene | caja.classList.contains('correcto') |
🧩 ¿Lo entendiste? · Practica
Crear elementos y armar texto
Hasta ahora trabajaste con elementos que ya existían. Ahora vas a crear elementos nuevos desde código, y a armar los textos que les pones adentro de una forma más prolija.
🧱 createElement, appendChild y remove
document.createElement("li") crea un elemento nuevo en memoria (todavía no se ve en la página). Le puedes poner texto con textContent antes de mostrarlo.
padre.appendChild(elemento) lo agrega como último hijo de "padre", y ahí aparece en pantalla. elemento.remove() lo saca del DOM directamente.
const nuevo = document.createElement('li');
nuevo.textContent = 'Nueva tarea';
lista.appendChild(nuevo);
tareaVieja.remove();
🧩 ¿Lo entendiste? · Practica
🧩 Template literals (backticks)
Un template literal se escribe con comillas invertidas (`) en vez de comillas simples o dobles. Dentro, insertas el valor de una variable con ${variable}.
También puedes poner expresiones dentro de ${ }, no solo variables sueltas: por ejemplo `Doble: ${puntos * 2}`.
`Hola ${nombre}, tienes ${puntos} pts`
| Con + | Con template literal |
|---|---|
"Hola " + nombre + "!" | `Hola ${nombre}!` |
"Puntos: " + (p*2) | `Puntos: ${p * 2}` |
🧩 ¿Lo entendiste? · Practica
👪 Juego: Buscando parientes
Un problema clásico: cada vez que una familia suma un integrante nuevo, alguien tiene que anotar quién es su padre o madre, y esa persona nueva debe aparecer colgando de esa rama en el árbol genealógico.
El HTML no puede traer ya escritas a todas las personas que todavía no existen — así que el árbol tiene que crecer con código, cada vez que alguien aprieta "Agregar". Esto combina las tres cosas que acabas de aprender:
Fíjate que el árbol crece en capas: si agregas a "Carlos" como hijo de "Rosa", y después agregas a "Ana" como hija de "Carlos", el <li> de Ana queda anidado dentro del de Carlos, que a su vez está anidado dentro del de Rosa.
| Paso del juego | Lo resuelve |
|---|---|
| Encontrar al padre o madre en el árbol | querySelector |
| Crear a la persona nueva y colgarla ahí | createElement + appendChild |
| Armar el texto "👤 nombre" | template literal |
🧩 ¿Lo entendiste? · Practica
📋 De inputs y arrays a elementos en pantalla
Los datos de un formulario HTML se leen o se escriben a través de la propiedad value de cada input seleccionado.
HTML de referencia
<input id="nombre" type="text"> <input id="edad" type="number">
JavaScript
document.getElementById("nombre").value = "HOMERO";
document.getElementById("edad").value = 39;
Y la misma propiedad funciona al revés: si el usuario ya escribió algo en el input, input.value te devuelve ese texto para que lo uses en tu código.
Ese valor casi siempre se combina con lo que ya sabes de createElement y for...of: recorres un Array de datos y, por cada uno, creas y agregas un elemento nuevo. Es exactamente el mismo patrón que usaste en el juego de parientes:
let padre = document.getElementById("personas");
let personas = ["HOMERO", "MARGE", "BART", "LISA", "MAGGIE"];
for (const persona of personas) {
let li = document.createElement("li");
li.innerHTML = persona;
padre.appendChild(li);
}
Si en vez de nombres sueltos tienes objetos (con varias propiedades cada uno), un template literal te permite armar de una sola vez todo el HTML interno de cada tarjeta:
const productos = [
{ id: 1, nombre: "Arroz", precio: 125 },
{ id: 2, nombre: "Fideo", precio: 70 },
{ id: 3, nombre: "Pan", precio: 50 },
{ id: 4, nombre: "Flan", precio: 100 }
];
for (const producto of productos) {
let tarjeta = document.createElement("div");
tarjeta.innerHTML = `<h3>ID: ${producto.id}</h3>
<p>Producto: ${producto.nombre}</p>
<b>$ ${producto.precio}</b>`;
document.body.appendChild(tarjeta);
}
🧩 ¿Lo entendiste? · Practica
Lee el valor del input con .value, crea un <li> con ese texto y agrégalo a la lista con appendChild.
Práctica integrada
Una misión chica que combina todo lo de este recurso: seleccionar, leer/escribir contenido, clases y crear elementos con template literals.
🎯 Misión: tarjeta de perfil interactiva
Tienes una tarjeta de estudiante con un botón para agregar una habilidad y un botón para marcarla como favorita. Completa el código para que funcione de punta a punta.
- Leer el nombre y el puntaje con
querySelectory armar el saludo con un template literal. - Agregar una nueva habilidad a la lista con
createElement+appendChild. - Marcar la tarjeta como favorita con
classListcuando se hace clic en la estrella.
Glosario
Todos los términos de este recurso, para repasar. Toca una tarjeta para girarla y ver la definición.
No encontré ningún término con esa búsqueda.