- Aprender
- Informática
- Programación
- Programación en JavaScript
- DOM en JavaScript
DOM en JavaScript: modelo de objetos del documento
PrincipianteUnidad 5 de 9 del curso Curso de Programación en JavaScript
Lo que aprenderás
- Explica qué es el modelo de objetos del documento, cómo lo construye el navegador a partir del HTML y cómo se relacionan sus nodos para que puedas orientarte en cualquier página.
- Describe el DOM como un árbol de nodosExplica qué es el DOM, cómo lo construye el navegador a partir del HTML, qué tipos de nodos contiene y en qué se diferencia del código fuente HTML.
- Navega desde un elemento hasta su padre, sus hijos y sus hermanosRecorre el árbol desde cualquier elemento hasta sus nodos relacionados, elige entre las propiedades que incluyen nodos de texto y las que solo devuelven elementos, y encuentra el antecesor coincidente más cercano.
- Describe el DOM como un árbol de nodos
- Encuentra exactamente los elementos que necesita un script con selectores CSS, maneja los elementos que faltan y trabaja con colecciones de elementos coincidentes.
- Selecciona un solo elementoEncuentra un elemento con querySelector o getElementById, busca dentro de una parte de la página y maneja el caso en que no hay ninguna coincidencia.
- Selecciona varios elementos y trabaja con los resultadosSelecciona todos los elementos coincidentes, recorre los resultados con un bucle, conviértelos en un array cuando sea necesario y reconoce cuándo una colección se actualiza por sí sola.
- Selecciona un solo elemento
- Actualiza lo que dicen los elementos y los atributos y propiedades que los controlan, elige el método seguro cuando el contenido procede de usuarios o datos y conserva información adicional en los elementos.
- Modifica el texto y el HTML dentro de un elementoLee y sustituye el contenido de un elemento con textContent, innerText e innerHTML, y protege las páginas frente al código inyectado.
- Lee y establece atributos y propiedadesTrabaja con atributos mediante getAttribute y setAttribute y con las propiedades correspondientes de los elementos, y maneja los atributos booleanos y las diferencias entre ambos.
- Almacena datos en elementos y lee campos de formularioConserva información adicional en los elementos mediante atributos de datos, y lee y establece el valor actual de los campos de formulario.
- Modifica el texto y el HTML dentro de un elemento
- Cambia clases CSS, establece estilos en línea cuando se calcula un valor, lee los estilos que aplica el navegador y muestra u oculta partes de una página.
- Añade, elimina y alterna clases CSSCambia la apariencia de un elemento alternando clases con classList y conserva las reglas visuales en la hoja de estilos.
- Establece estilos en línea y lee estilos calculadosEstablece estilos en línea mediante la propiedad style cuando se calcula un valor en tiempo de ejecución, elimínalos y lee los estilos que el navegador aplica realmente.
- Muestra y oculta partes de una páginaOculta y muestra elementos con el atributo hidden o con una clase, elige entre las formas en que CSS puede hacer algo invisible y mantén claro el estado para los usuarios de lectores de pantalla.
- Añade, elimina y alterna clases CSS
- Construye elementos nuevos en JavaScript, colócalos exactamente donde corresponden y elimina, sustituye o copia elementos para que la página cambie sin recargarse.
- Crea elementos nuevos e insértalosCrea elementos con createElement, rellénalos con texto y atributos e insértalos al final, al principio o junto a otro elemento.
- Elimina, sustituye y copia elementosRetira elementos de la página, vacía un contenedor, sustituye un elemento por otro y haz copias con cloneNode.
- Crea elementos nuevos e insértalos
- Convierte arrays de datos en listas y tablas en la página, construye muchos elementos de forma eficiente y mantén la página sincronizada con los datos a medida que cambian.
- Construye elementos de lista y filas de tabla a partir de un arrayConvierte un array de objetos en elementos de lista o filas de tabla con textContent, muestra una salida adecuada para listas vacías y valores ausentes, y vincula cada elemento con sus datos.
- Construye muchos elementos de forma eficiente con fragmentos y plantillasInserta muchos elementos nuevos en un solo paso con un DocumentFragment o una sola llamada a append, y reutiliza el marcado escrito en un elemento de plantilla HTML.
- Actualiza la página cuando cambien los datosMantén los datos como única fuente de verdad, vuelve a renderizar a partir de ellos después de cada cambio y muestra vistas filtradas, ordenadas y de resumen sin perder los datos originales.
- Construye elementos de lista y filas de tabla a partir de un array
Guía de estudio de DOM en JavaScript
1Lee la página como un árbol
El navegador convierte el HTML en objetos que JavaScript puede leer y modificar. Esos objetos forman un árbol, por lo que encontrar un elemento de la página también implica comprender dónde se sitúa entre otros nodos. Empieza relacionando las etiquetas conocidas con los objetos del navegador. Después, sigue las relaciones entre padres, hijos y hermanos, prestando atención a los nodos de texto creados a partir de espacios y saltos de línea. Las herramientas de desarrollo te permiten ver este árbol mientras tu código lo modifica.
1.1 El HTML se convierte en un árbol de objetos
El modelo de objetos del documento, o DOM, es el árbol dinámico de objetos de la página que mantiene el navegador. JavaScript lee y modifica estos objetos para actualizar la página sin recargarla. El navegador proporciona la API del DOM; JavaScript es el lenguaje que se usa para llamarla.
Empieza por el documento
document es el punto de entrada. document.documentElement se refiere a <html>, document.head a <head> y document.body a <body>. La pestaña del navegador está representada por window, cuya propiedad document se refiere a este documento.
Cada elemento del árbol es un nodo. Los elementos representan etiquetas; los nodos de texto contienen caracteres; los nodos de comentario contienen comentarios HTML; el nodo de documento está por encima de los elementos de la página. Sus valores de nodeType son 1, 3, 8 y 9, respectivamente. Todo elemento es un nodo, pero el texto y los comentarios no son elementos.
Lee las relaciones familiares
<ul id="menu"><li>Home</li><li>About</li></ul>
La lista es el padre de dos elementos de lista hermanos. Cada uno es su hijo. El primero tiene un nodo de texto hijo que contiene «Home». La lista es un antecesor de ese nodo de texto y el texto es un descendiente de la lista. Estas relaciones describen el anidamiento, no las posiciones en la pantalla.
Los espacios y saltos de línea entre etiquetas suelen convertirse en nodos de texto con espacios en blanco. Por tanto, una lista sangrada puede tener dos elementos hijos, pero más de dos nodos hijos. children y firstElementChild devuelven solo elementos; childNodes y firstChild incluyen texto y comentarios.
Compara el árbol con el código fuente
El análisis sintáctico convierte el marcado en el árbol y puede completarlo o repararlo. Las filas escritas directamente dentro de una <table> adquieren un padre <tbody>. También pueden añadirse los elementos <html>, <head> o <body> que falten. Selecciona a partir del árbol real, incluidos estos elementos añadidos por el analizador.
Los cambios de un script afectan al DOM actual del navegador, no al archivo HTML del servidor. «Ver código fuente de la página» muestra el HTML original, mientras que el panel Elementos de las herramientas de desarrollo muestra el árbol actual. Al recargar se construye un DOM nuevo; una edición por sí sola no guarda los datos que la sustentan.
Inspecciona un objeto
Haz clic derecho en un elemento y elige «Inspeccionar». Introduce $0 en la consola para referirte al elemento seleccionado. console.log($0) lo presenta como marcado; console.dir($0) muestra sus propiedades. Despliega una lista sangrada para ver los nodos de espacios en blanco junto a sus elementos de lista.
Puntos clave
- El DOM es un árbol proporcionado por el navegador que JavaScript puede leer y modificar.
- Los elementos, el texto, los comentarios y el documento son distintos tipos de nodos.
- Los espacios en blanco y los elementos añadidos por el analizador pueden hacer que el DOM difiera del HTML escrito.
- Inspecciona el árbol actual en las herramientas de desarrollo; una edición del DOM no reescribe el HTML del servidor.
1.2 Sigue las relaciones entre padres, hijos y hermanos
Las propiedades del árbol permiten que un script llegue al contenido cercano desde un elemento que ya tiene. Elige si esa ruta debe incluir texto y comentarios o solo elementos.
Elige nodos o elementos
Las propiedades de nodos incluyen parentNode, childNodes, firstChild, lastChild, previousSibling y nextSibling. Sus equivalentes para elementos son parentElement, children, firstElementChild, lastElementChild, previousElementSibling y nextElementSibling. children es una HTMLCollection; childNodes es una NodeList.
<ul id="tasks">
<li>Buy milk</li>
<li>Call Sam</li>
</ul>
Aquí tasks.childNodes.length es 5: dos elementos y tres secuencias de espacios en blanco. tasks.children.length es 2. tasks.firstChild es texto con espacios en blanco, mientras que tasks.firstElementChild.textContent es «Buy milk». Los índices empiezan en 0, por lo que tasks.children[1] es el segundo elemento de la lista.
Sigue una ruta corta
const tasks = document.querySelector("#tasks");
const first = tasks.firstElementChild;
const second = first.nextElementSibling;
console.log(second.textContent);
console.log(second.parentElement === tasks);
La salida es «Call Sam» y después true. tasks.lastElementChild llega directamente al mismo elemento, igual que tasks.children[tasks.children.length - 1].
Maneja un nodo relacionado ausente
El nextElementSibling del último elemento es null. Un elemento sin hijos de tipo elemento tiene firstElementChild === null y una colección children vacía. El parentNode del elemento HTML raíz es el documento, pero su parentElement es null.
Leer una propiedad de null lanza un error de tipo. Comprueba primero o usa second.nextElementSibling?.textContent, que da undefined cuando no existe un elemento siguiente.
Encuentra un elemento contenedor
closest(selector) comprueba el elemento actual y después sus antecesores, y devuelve la coincidencia más cercana o null. Un botón dentro de <li class="task" data-id="7"> puede usar button.closest(".task"); el dataset.id del elemento coincidente es «7». En cambio, matches(selector) comprueba solo el elemento actual y devuelve un booleano.
Las rutas largas como el.parentElement.parentElement.nextElementSibling dependen del anidamiento exacto. Añadir un contenedor cambia su significado. Usa selectores para regiones con nombre, navegación corta para relaciones estables y closest() para un elemento contenedor.
Puntos clave
- Usa la navegación exclusiva de elementos cuando deban omitirse los espacios en blanco y los comentarios.
- Las colecciones empiezan en el índice 0; su longitud es un recuento, no el último índice.
- Un nodo relacionado ausente es null; compruébalo antes de leerlo.
- closest() comprueba el propio elemento y después sus antecesores.
- matches() comprueba el elemento actual sin desplazarse por el árbol.
2Encuentra elementos de la página
Un cambio en el DOM comienza con una referencia al elemento correcto. Los selectores CSS permiten buscar en toda la página o solo en un contenedor, mientras que los métodos de colección permiten trabajar con muchos resultados. El valor de retorno importa: una búsqueda puede dar un elemento o null, otra siempre da una colección. También necesitarás saber cuándo se ejecuta el script y si una colección guardada cambia cuando cambia la página, porque ambos factores afectan a lo que encuentra tu código.
2.1 Encuentra un elemento y comprueba el resultado
Un selector convierte la descripción de un elemento en una referencia a un objeto. Empieza con la búsqueda más acotada que identifique el elemento que necesitas y comprueba que se haya encontrado antes de modificarlo.
Busca con un selector CSS o un id
document.querySelector(selector) devuelve el primer elemento coincidente en el orden del documento. Acepta selectores CSS conocidos: "h1", ".price", "#cart", "nav a" o 'input[type="email"]'. Si no hay coincidencias, devuelve null.
document.getElementById("cart") busca directamente un id. Su argumento es el id sin más. getElementById("#cart") busca un id que realmente incluye la almohadilla, mientras que querySelector("cart") busca una etiqueta <cart>. Usa querySelector("#cart") para el selector de id.
Los id deben ser únicos. Si el marcado copiado asigna el mismo id a dos elementos, estas búsquedas devuelven el primero en el orden del documento. Corrige el marcado duplicado en lugar de esperar que una búsqueda por id llegue a la segunda copia.
Busca dentro de un contenedor
Supón que varias tarjetas tienen un elemento con la clase name. Selecciona primero la tarjeta de perfil y después busca entre sus descendientes:
const card = document.querySelector("#profile");
if (card) {
const name = card.querySelector(".name");
if (name) name.textContent = "Maya";
}
La búsqueda interna se limita a la tarjeta de perfil, por lo que un .name anterior en otra parte no interfiere. El propio contenedor no es candidato en su búsqueda con querySelector(). Los elementos ordinarios admiten este método, pero getElementById() pertenece a document.
Distingue entre la ausencia de coincidencias y un selector no válido
Una búsqueda válida sin coincidencias da null. Intentar asignar un valor a null.textContent lanza un error de tipo, así que comprueba el contenido opcional:
const banner = document.querySelector(".banner");
if (banner) banner.textContent = "Sale ends Friday";
Un selector CSS no válido lanza un error de sintaxis antes de que pueda haber un resultado. Para <p id="1st">, querySelector("#1st") no es válido porque el dígito necesita una secuencia de escape en ese selector CSS de id. getElementById("1st") usa un id literal y funciona directamente.
Ejecuta el código después de que exista el marcado necesario
Un script externo clásico en <head> se ejecuta antes de que el navegador haya analizado el cuerpo. Por tanto, una búsqueda de un párrafo posterior devuelve null aunque el HTML lo contenga. Usa <script src="app.js" defer></script> para ejecutarlo después del análisis, usa un script de módulo o coloca el script justo antes de </body>. Los scripts de módulo se difieren de forma predeterminada. El atributo defer no tiene efecto en un script clásico integrado en HTML.
En una página HTML que comienza con <!DOCTYPE html>, los selectores de id y clase distinguen entre mayúsculas y minúsculas: .Price no coincide con class="price". Los selectores de etiquetas HTML no las distinguen, por lo que "LI" y "li" coinciden con elementos de lista. Cuando una búsqueda falle, comprueba la escritura, la sintaxis del selector, el contenedor de búsqueda y el momento de ejecución del script.
Puntos clave
- querySelector() devuelve la primera coincidencia o null.
- getElementById() recibe un id sin prefijo; querySelector() recibe sintaxis de selector CSS.
- Busca entre los descendientes de un contenedor cuando una clase aparece en varias regiones de la página.
- Una búsqueda sin coincidencias devuelve null; una sintaxis de selector no válida lanza un error.
- Ejecuta el código DOM después de que se haya analizado su marcado.
- Mantén los id únicos y respeta las mayúsculas y minúsculas en los selectores de id y clase.
2.2 Trabaja con colecciones de elementos coincidentes
Usa querySelectorAll() cuando corresponda realizar la misma operación en varios elementos. Su resultado es una colección, así que debes decidir cómo recorrerla y si necesitas una instantánea o una vista dinámica.
Lee y recorre una NodeList
document.querySelectorAll(".note") devuelve una NodeList de elementos coincidentes en el orden del documento. Si no hay coincidencias, devuelve una NodeList vacía de longitud 0. La propia colección sigue siendo verdadera en contexto booleano; if (notes) no indica si contiene elementos. Comprueba notes.length.
Una NodeList admite índices, length, forEach() y for...of, pero no es un array y no tiene map(), filter() ni reduce(). Conviértela cuando necesites esos métodos:
const weights = Array.from(document.querySelectorAll(".weight"))
.map(el => Number(el.textContent));
const total = weights.reduce((sum, weight) => sum + weight, 0);
Para elementos que contienen «4.5», «12» y «3.25», el array es [4.5, 12, 3.25] y el total es 19,75 kg. La conversión a números es importante porque los valores de texto son cadenas.
Una colección no es un elemento combinado. Asignar un valor a notes.textContent no modifica ninguna nota, y notes.classList.add("saved") lanza un error porque la NodeList no tiene classList. Aplica el cambio a cada elemento:
const notes = document.querySelectorAll(".note");
notes.forEach(note => note.classList.add("saved"));
Compara resultados estáticos y dinámicos
La NodeList de querySelectorAll() es estática: sus miembros quedan fijados cuando se ejecuta la búsqueda. Los elementos a los que se refiere siguen siendo los objetos reales, por lo que su texto o sus clases pueden cambiar.
getElementsByClassName("note") y getElementsByTagName("li") devuelven una HTMLCollection dinámica. children también es dinámica. Estas colecciones actualizan sus miembros cuando cambia el DOM. Admiten índices y for...of, pero no forEach().
En una lista con tres elementos .item, guarda tanto list.getElementsByClassName("item") como list.querySelectorAll(".item"). Añade un cuarto elemento coincidente. La colección dinámica tiene ahora longitud 4; la instantánea sigue teniendo longitud 3.
Evita el problema de recorrer una colección dinámica que se reduce
Supón que cuatro elementos pertenecen a una colección dinámica llamada live:
for (let i = 0; i < live.length; i++) {
live[i].classList.remove("item");
}
Eliminar la primera clase saca ese elemento de la colección. El siguiente elemento se desplaza al índice 0, pero el bucle avanza al índice 1 y lo omite. Solo dos de los cuatro pierden la clase. Recorre Array.from(live) o una instantánea de querySelectorAll() cuando cambies los miembros de la colección.
Comprueba los espacios en los selectores
.task.done significa un elemento con ambas clases. .task .done significa un descendiente .done dentro de un .task. Para <li class="task done">, cuenta los elementos terminados con document.querySelectorAll(".task.done").length. Una coma combina selectores: "h2, h3" devuelve las coincidencias en el orden del documento, no todos los encabezados de un tipo seguidos por los del otro.
Puntos clave
- Recorre los miembros de una colección para modificar su contenido o sus clases.
- querySelectorAll() devuelve una NodeList estática; un resultado vacío tiene longitud 0.
- Convierte las colecciones con Array.from() o la sintaxis de propagación antes de usar métodos exclusivos de arrays.
- Los miembros de las colecciones dinámicas cambian cuando cambian los elementos coincidentes.
- Toma una instantánea antes de un bucle que elimine miembros de una colección dinámica.
- Un espacio en un selector cambia la relación que se busca.
3Actualiza el contenido y los datos de los elementos
Un elemento contiene varios tipos de información: texto visible, estructura HTML, atributos y propiedades de JavaScript. Elegir el adecuado te permite actualizar una etiqueta, cambiar un enlace, leer un campo o conectar un elemento mostrado con sus datos. El mismo texto puede tratarse como caracteres ordinarios o analizarse como HTML, con resultados muy diferentes. Presta atención a estas diferencias para que las actualizaciones muestren el contenido previsto y el texto externo se mantenga seguro.
3.1 Elige texto o HTML para actualizar el contenido
El texto y el HTML son entradas diferentes. El texto sin formato debe aparecer como caracteres; el HTML describe elementos que el navegador debe construir. Elegir entre ellos afecta tanto a la estructura de la página como a la posibilidad de que el texto externo ejecute código no deseado.
Lee y sustituye texto
Para <p id="msg">Total: <strong>3</strong> items</p>, msg.textContent es «Total: 3 items». Une el texto de los descendientes del elemento sin incluir sus etiquetas e incluye el texto oculto por CSS.
Asignar un valor a textContent sustituye todos los hijos por un nodo de texto. Después de msg.textContent = "Cart is empty", el hijo <strong> ya no existe dentro del párrafo. Asignar msg.textContent = "<b>Hi</b>" muestra los caracteres literales «Hi»; no crea ningún elemento en negrita.
Los valores de texto son cadenas. Si un contador contiene «4», count.textContent + 1 produce «41». Convierte antes de sumar:
count.textContent = Number(count.textContent) + 1;
La suma da el número 5 y la asignación muestra su forma textual, «5».
Lee el texto que sigue la disposición visual
En un elemento renderizado, innerText sigue el texto mostrado y la disposición visual. Omite los descendientes ocultos con display: none e incluye saltos de línea que siguen la disposición. Leerlo puede requerir un cálculo de la disposición. Usa textContent para el trabajo habitual con texto; elige innerText cuando necesites el texto renderizado. Si el propio elemento está desconectado o no se renderiza, innerText recurre a su contenido de texto.
Analiza HTML de forma deliberada
innerHTML lee el marcado dentro de un elemento. Al asignarle un valor, analiza la cadena y sustituye los hijos:
msg.innerHTML = "Total: <strong>5</strong> items";
Esto crea un nuevo elemento <strong>. Es adecuado para marcado que hayas escrito y controles. Para texto de un usuario o datos externos, usa textContent y construye la estructura con createElement().
Insertar HTML no fiable puede permitir secuencias de comandos entre sitios (XSS): el código controlado por un atacante se ejecuta en el navegador del visitante. Una imagen inyectada puede llevar un atributo onerror que ejecuta código cuando la imagen no se carga. Las etiquetas de script insertadas por innerHTML no se ejecutan, pero eso no hace seguro el resto del HTML inyectado. Bloquear solo las etiquetas de script deja abierta esta vía de ataque.
Conserva los hijos existentes al añadir contenido
list.innerHTML += "<li>New</li>" lee el marcado existente, le une una cadena y después analiza y sustituye todo el conjunto de hijos. No conserva su identidad de objeto. Una variable que contiene un hijo antiguo sigue guardando ese objeto desconectado, y los valores escritos en los campos de entrada sustituidos pueden perderse. Usa append() con nodos nuevos o insertAdjacentHTML("beforeend", markup) para marcado fiable, para añadir contenido sin volver a crear los hijos existentes.
outerHTML incluye la propia etiqueta del elemento además de su contenido. Al asignarle un valor, sustituye el propio elemento. Una referencia guardada sigue apuntando al elemento antiguo desconectado después de esa sustitución; no cambia automáticamente al nuevo.
Puntos clave
- textContent maneja texto sin formato y sustituye los hijos del elemento cuando se le asigna un valor.
- Convierte el texto en un número antes de realizar operaciones aritméticas.
- innerText sigue la disposición renderizada; innerHTML analiza el marcado.
- Mantén el texto no fiable fuera de las asignaciones que analizan HTML.
- innerHTML += vuelve a crear los hijos existentes; append() los conserva.
- La asignación a outerHTML sustituye el elemento y deja desconectadas las referencias antiguas.
3.2 Distingue los atributos de las propiedades de los objetos
Un atributo es un nombre y un valor en HTML. Una propiedad pertenece al objeto JavaScript que representa un elemento. Muchos atributos estándar tienen propiedades correspondientes, pero estas pueden procesar valores o indicar un tipo de estado diferente.
Trabaja con un atributo por su nombre
Para <img src="logo.png" alt="Company logo">, el navegador inicializa propiedades como img.src e img.alt. También puedes usar métodos que reciben el nombre del atributo como cadena:
getAttribute(name)devuelve una cadena onullsi el atributo no existe.setAttribute(name, value)añade o modifica un atributo y almacena su valor como texto.hasAttribute(name)indica si el atributo está presente.removeAttribute(name)lo elimina.
Por ejemplo, link.setAttribute("href", "https://example.com/help") cambia el destino de un enlace. Si no hay ningún atributo target, link.getAttribute("target") devuelve null, no una cadena vacía.
Lee el valor que realmente necesitas
En una página situada en https://example.com/shop/, el enlace <a href="/about"> tiene el valor de atributo «/about». Su propiedad href es la URL resuelta, «https://example.com/about». Lee el atributo cuando necesites el valor exactamente como está escrito y la propiedad cuando necesites la URL resuelta.
Las propiedades pueden tener tipos distintos de cadena. button.disabled es un booleano; input.maxLength es un número. Los métodos de atributos siguen devolviendo cadenas o null. Los nombres de propiedades también son nombres de JavaScript que distinguen entre mayúsculas y minúsculas: el.id funciona, mientras que el.ID es una propiedad diferente y normalmente es undefined.
La mayoría de los nombres son conocidos, pero hay excepciones. El atributo HTML class se expone mediante className y classList. El atributo for de una etiqueta es su propiedad htmlFor:
label.htmlFor = "email";
Esto asocia la etiqueta con el elemento cuyo id es «email».
Trata los atributos booleanos según su presencia
Los atributos booleanos incluyen disabled, checked, required y readonly. Su presencia hace que el atributo sea verdadero, aunque su texto sea «false». Este código deshabilita un botón:
button.setAttribute("disabled", "false");
Para habilitarlo, asigna button.disabled = false o llama a button.removeAttribute("disabled"). button.toggleAttribute("disabled", isBusy) añade el atributo cuando isBusy es verdadero y lo elimina cuando es falso.
Describe los controles de forma accesible
Los atributos ARIA proporcionan información a las tecnologías de apoyo. Los métodos de atributos son útiles para establecerlos, como button.setAttribute("aria-label", "Close dialog") para dar nombre a un botón que solo contiene un icono. Sus valores son cadenas; por ejemplo, un valor de estado expandido es «true» o «false».
Usa propiedades para operaciones habituales como img.src = "photo.jpg" o input.disabled = true. Usa métodos de atributos cuando el nombre esté guardado en una variable, el valor escrito exacto sea relevante o el atributo no tenga una propiedad correspondiente que estés usando.
Sigue un cambio de propiedad hasta el HTML
const field = document.createElement("input");
field.disabled = true;
console.log(field.hasAttribute("disabled"));
console.log(typeof field.disabled);
console.log(typeof field.getAttribute("disabled"));
field.removeAttribute("disabled");
console.log(field.disabled);
Las salidas son true, «boolean», «string» y false. Asignar el valor a la propiedad añade el atributo booleano. Leer ese atributo sigue devolviendo texto, aunque la propiedad sea booleana. Eliminarlo devuelve la propiedad a falso. El método y la propiedad muestran la misma presencia mediante distintos tipos de valor.
Puntos clave
- Los atributos almacenan valores HTML; las propiedades pueden mostrar valores tipados o procesados.
- getAttribute() devuelve una cadena o null cuando el atributo no existe.
- Los atributos booleanos son verdaderos por su presencia, incluido disabled="false".
- Usa nombres de propiedades como className y htmlFor cuando difieran de los nombres HTML.
- Los valores ARIA son cadenas que describen el elemento a las tecnologías de apoyo.
3.3 Conecta elementos con datos y lee campos
Un elemento puede llevar un id de los datos que muestra sin mostrar ese id en pantalla. Los controles de formulario también contienen valores, pero su contenido actual se lee mediante propiedades. Ambos tipos de valores suelen necesitar una conversión antes de compararlos o realizar operaciones aritméticas.
Almacena datos personalizados con atributos de datos
Los nombres HTML que empiezan por data- almacenan información para los scripts:
<li data-task-id="17" data-priority="high">Prepare slides</li>
El objeto dataset permite acceder a estos atributos. Elimina el prefijo data- y convierte cada guion seguido de una letra minúscula en esa letra mayúscula: data-task-id pasa a ser dataset.taskId. data-priority pasa a ser dataset.priority.
li.dataset.dueDate = "2026-11-05";
delete li.dataset.priority;
La asignación crea data-due-date="2026-11-05". delete elimina data-priority. Los atributos de datos también pueden seleccionarse con selectores CSS de atributo, como '[data-priority="high"]'.
Un atributo inventado como taskid="17" no es HTML válido y no crea ninguna propiedad li.taskid. getAttribute("taskid") aún puede leerlo, pero data-task-id es la forma adecuada para datos personalizados.
Convierte los valores de cadena de forma deliberada
li.dataset.taskId es «17», una cadena. li.dataset.taskId === 17 es falso porque los tipos son diferentes. Cuando los id de los datos son números, usa Number(li.dataset.taskId) === 17. Un atributo de datos ausente da undefined. Asignar li.dataset.count = 3 almacena el texto «3».
Esto ofrece un vínculo útil desde un elemento mostrado hasta su objeto:
const id = Number(li.dataset.taskId);
const task = tasks.find(task => task.id === id);
La comparación usa ahora dos números. Si ningún objeto tiene ese id, find() devuelve undefined; compruébalo antes de leer sus propiedades.
Lee el valor actual de un campo
Un <input> no contiene el valor escrito como contenido de texto. Lee input.value, que es una cadena, o asígnale un valor para cambiar el campo. input.value = "" lo vacía.
Para <input id="qty" value="1">, después de que el usuario escriba 3, qty.value es «3», pero qty.getAttribute("value") sigue siendo «1». El atributo proporciona el valor inicial; la propiedad proporciona el actual. Una casilla de verificación funciona de forma similar: su propiedad checked indica su estado booleano actual, mientras que el atributo describe el estado inicial de selección.
Usa el valor adecuado para cada control
Incluso <input type="number"> tiene un value de tipo cadena. Si la cantidad es «3» y cada elemento pesa 0,25 kg, Number(qty.value) * 0.25 da 0,75 kg. Pero qty.value + 1 da «31» porque + une una cadena y un número. Un <select> devuelve el valor de la opción seleccionada mediante select.value. Para una casilla de verificación, lee checkbox.checked, no checkbox.value, cuando necesites saber si está seleccionada.
Puntos clave
- dataset relaciona data-task-id con taskId y almacena valores de cadena.
- Usa delete en una propiedad de dataset para eliminar su atributo de datos.
- Convierte los id de datos antes de compararlos de forma estricta con id numéricos.
- Lee el contenido actual de input y select mediante value.
- Lee el estado actual de selección de una casilla de verificación mediante checked.
- Los atributos iniciales value y checked pueden diferir de las propiedades actuales del control.
4Controla la apariencia y la visibilidad
JavaScript puede cambiar la apariencia de una página al alternar clases, establecer un valor calculado en línea u ocultar una sección. Estas opciones funcionan con el CSS que ya existe en la página. Aprende qué estado corresponde a una clase, qué valores necesitan unidades y cómo leer el estilo que aplica el navegador. Mostrar y ocultar también afecta a la disposición visual y a las tecnologías de apoyo, así que mantén sincronizados los paneles visibles y sus atributos de accesibilidad.
4.1 Cambia clases sin perder el estilo base
Mantén las reglas visuales fijas en CSS y deja que JavaScript cambie las clases que seleccionan esas reglas. Una clase puede expresar estados como «terminado», «activo» o «error» sin repetir en el código los colores y las decoraciones correspondientes.
Añade y elimina nombres de clase
Supón que la hoja de estilos contiene:
.done { text-decoration: line-through; color: #888; }
item.classList.add("done") aplica el aspecto de elemento terminado. item.classList.remove("done") elimina ese estado y deja intactas las demás clases. Ambos métodos aceptan varios nombres; añadir una clase existente o eliminar una ausente no causa problemas.
contains("done") devuelve un booleano. replace("wide", "narrow") sustituye una clase presente por otra. toggle("active") añade una clase ausente o elimina una presente y devuelve si la clase queda presente.
Sigue un cambio de clase
Empieza con <div class="card">:
card.classList.add("active", "wide");
const active = card.classList.toggle("active");
const replaced = card.classList.replace("wide", "narrow");
Después de la primera línea, las clases son «card active wide». La alternancia elimina «active», por lo que active es false y las clases pasan a ser «card wide». Al sustituir «wide», quedan «card narrow» y se devuelve true. Una llamada posterior a card.classList.contains("active") da false.
Establece una clase a partir de una condición
Cuando los datos indican el estado deseado, pasa un segundo argumento:
row.classList.toggle("overdue", daysLeft < 0);
Un daysLeft negativo garantiza la presencia de la clase; en caso contrario, la clase está ausente. Repetir la llamada conserva ese estado. Una llamada simple a toggle("overdue") lo invertiría en cada ejecución.
Conserva el resto del atributo de clase
className es la cadena completa de clases. card.className = "active" sustituye todas las clases existentes, incluida «card». Usa esta asignación cuando quieras sustituir todo el conjunto; usa classList para cambiar estados individuales.
Pasa los nombres de clase sin prefijos ni signos de selector CSS. classList.add(".active") añade un nombre que contiene un punto literal; no es la clase con la que coincide .active. Un solo argumento no puede contener espacios: classList.add("big red") lanza un InvalidCharacterError. Escribe classList.add("big", "red") para dos clases.
Comprueba el CSS cuando el aspecto no cambia
Si una clase no tiene un efecto visible, inspecciona su nombre y su regla en las herramientas de desarrollo. Comprueba si falta una regla, si está mal escrita o si hay declaraciones anuladas que aparecen tachadas en el panel Estilos.
Puntos clave
- classList cambia nombres de clase individuales y conserva las demás clases.
- toggle(name) devuelve si la clase queda presente.
- toggle(name, condition) establece una clase a partir de los datos sin invertirla en cada ejecución.
- La asignación a className sustituye toda la cadena de clases.
- Pasa nombres separados y sin prefijos, puntos de selector ni espacios dentro de un nombre.
4.2 Establece estilos calculados y lee estilos aplicados
Usa clases para diseños fijos y estilos en línea para valores calculados. El objeto style lee y escribe declaraciones en línea, no todas las reglas que afectan a un elemento.
Escribe valores CSS mediante style
Los nombres CSS con guiones se convierten en propiedades JavaScript con notación camelCase. background-color pasa a ser backgroundColor, font-size pasa a ser fontSize y z-index pasa a ser zIndex:
box.style.backgroundColor = "gold";
box.style.width = "250px";
Los valores de estilo son cadenas. Incluye una unidad cuando la propiedad la requiera. En una página en modo estándar, la asignación box.style.width = 250 se ignora porque una anchura distinta de cero necesita una unidad CSS. La cadena «0» es válida para una anchura de cero.
En cambio, style.setProperty() recibe el nombre tal como se escribe en CSS:
box.style.setProperty("background-color", "gold");
document.documentElement.style.setProperty("--accent", "#0a7d5a");
La propiedad personalizada de la raíz proporciona el valor a las reglas que hacen referencia a var(--accent).
Convierte un cálculo en un valor CSS
Una barra de progreso muestra 3 tareas terminadas de un total de 8:
const percent = (3 / 8) * 100;
bar.style.width = `${percent}%`;
La proporción 0,375 se convierte en 37,5 %. El literal de plantilla proporciona «37.5%», incluida la unidad necesaria.
Elimina una sobrescritura temporal
Asigna box.style.backgroundColor = "" o llama a box.style.removeProperty("background-color") para eliminar esa declaración en línea. Entonces el navegador aplica las reglas restantes de la hoja de estilos. Usa el nombre CSS con guiones en removeProperty().
Ten cuidado con style.cssText. Asignar box.style.cssText = "color: red" sustituye todo el estilo en línea, por lo que se pierde cualquier anchura en línea existente. Cambiar una propiedad de estilo deja intactas las demás declaraciones en línea.
Lee lo que aplica el navegador
Si una hoja de estilos hace que un párrafo sea rojo, pero este no tiene un color en línea, p.style.color es una cadena vacía. Usa getComputedStyle(p).color para obtener el valor aplicado, normalmente «rgb(255, 0, 0)». Los valores calculados son de solo lectura; cambia la clase o la declaración en línea para modificar el aspecto.
Las declaraciones en línea prevalecen sobre las reglas ordinarias de la hoja de estilos, pero las declaraciones !important aplicables pueden prevalecer sobre ellas. Si un cambio de clase parece no surtir efecto, comprueba si queda una sobrescritura en línea.
Puntos clave
- style lee y escribe declaraciones en línea; la notación camelCase corresponde a nombres CSS con guiones.
- Incluye unidades en las cadenas de valores CSS cuando sean necesarias.
- setProperty() y removeProperty() reciben nombres CSS con guiones.
- Elimina una declaración en línea para que las reglas de la hoja de estilos vuelvan a aplicarse.
- getComputedStyle() proporciona los valores aplicados, incluidos los estilos de reglas CSS.
4.3 Oculta contenido y mantén claro su estado
Ocultar un panel lo deja en el DOM, listo para volver a aparecer con su contenido y los valores de sus campos. Eliminarlo lo saca del árbol. Elige la ocultación para un panel que volverá a aparecer y la eliminación para un elemento cuyos datos ya no existen.
Usa la propiedad hidden
panel.hidden = true añade el estado oculto ordinario. El estilo predeterminado del navegador oculta el panel sin que ocupe espacio en la disposición visual. panel.hidden = false elimina ese estado y vuelve a mostrarlo.
Una hoja de estilos puede anular este comportamiento predeterminado. Por ejemplo, .panel { display: flex; } puede hacer visible un panel oculto. Cuando el estado oculto deba prevalecer siempre, incluye:
[hidden] { display: none !important; }
Otra opción es controlar la visibilidad con una clase CSS. Con .is-hidden { display: none; }, menu.classList.toggle("is-hidden", !isOpen) añade la clase de ocultación cuando el menú está cerrado. Comprueba la hoja de estilos si la clase está presente pero prevalece otra declaración de display.
Compara tres formas de ocultar
display: none elimina el espacio del elemento en la disposición visual y lo oculta a los lectores de pantalla. visibility: hidden lo hace invisible mientras conserva su espacio y también lo oculta a los lectores de pantalla. opacity: 0 lo hace transparente, pero conserva su espacio; aún se puede hacer clic en él y sigue disponible para los lectores de pantalla. Por tanto, la transparencia por sí sola no es una buena forma de cerrar un panel que ya no debe estar disponible.
Estos efectos afectan a la visibilidad y a la disposición visual, no a la eliminación. Un campo de entrada oculto puede conservar el valor escrito en él porque el mismo objeto permanece en el árbol.
Mantén sincronizada la descripción del control
Un botón asociado a un panel desplegable debe indicar si está expandido. Establece aria-expanded en la cadena «true» cuando esté abierto y en «false» cuando esté cerrado. Basa ese valor y la visibilidad del panel en el mismo estado.
Para un panel de respuesta que comienza como <div id="answer-1" hidden>, con referencias llamadas answer y button, ejecuta:
const willOpen = answer.hidden;
answer.hidden = !willOpen;
button.setAttribute("aria-expanded", String(willOpen));
Al principio answer.hidden es true, por lo que willOpen es verdadero. La asignación establece hidden en falso y muestra el panel. El atributo del botón pasa a ser «true». Al ejecutar las mismas sentencias de nuevo, se parte de hidden en falso, se oculta el panel y se escribe «false» en el atributo.
Diagnostica una discordancia
Si el botón anuncia «expandido» mientras el panel está oculto, los dos valores no se actualizaron juntos. Si hidden es verdadero pero el panel sigue visible, inspecciona su display calculado y la regla CSS responsable. El primer problema es un estado incoherente de la aplicación; el segundo es un estilo que anula el estado oculto. Leer tanto las propiedades del DOM como el CSS aplicado te permite distinguirlos.
Puntos clave
- hidden mantiene el contenido en el DOM mientras lo oculta con el estilo predeterminado.
- Una regla display explícita puede anular hidden; inspecciona o haz prevalecer la regla prevista.
- display: none elimina el espacio; visibility: hidden lo conserva.
- opacity: 0 conserva la interacción y la disponibilidad para lectores de pantalla.
- Actualiza aria-expanded a partir del mismo estado de apertura que el panel.
5Construye y modifica la estructura de la página
La estructura de una página puede cambiar mientras está abierta. Construye un elemento en memoria, rellénalo e insértalo en el punto correcto del árbol. Los mismos métodos de inserción pueden mover un nodo existente, por lo que añadir una referencia dos veces no crea dos copias. Eliminar, sustituir y clonar producen cambios diferentes en el árbol y en las referencias que conserva tu script. Seguir esas referencias ayuda a explicar por qué una variable antigua a veces apunta a contenido desconectado.
5.1 Crea un nodo, rellénalo e insértalo
Un elemento nuevo no aparece solo porque lo hayas creado. Primero crea el objeto, después dale contenido y atributos y, por último, insértalo en el documento. Antes de insertarlo, puedes construir toda una estructura anidada en memoria.
Construye un elemento completo
const li = document.createElement("li");
li.textContent = "Water the plants";
li.className = "task";
li.dataset.id = "4";
document.querySelector("#tasks").append(li);
createElement("li") crea un elemento vacío. Las líneas siguientes lo rellenan; la última lo inserta como último hijo de la lista de tareas existente. Produce <li class="task" data-id="4">Water the plants</li>. La llamada necesita un nombre de etiqueta, no marcado: createElement("<li>") lanza un InvalidCharacterError. Establece las clases y los atributos después de la creación.
Para contenido anidado, crea por separado un span para el título y un botón, establece su texto y llama a li.append(title, button). Después inserta el elemento construido en la lista. document.createTextNode("…") crea texto directamente; pasar una cadena a append() también inserta un nodo de texto.
Elige una posición de inserción
parent.append(...)añade después de los hijos existentes.parent.prepend(...)añade antes de los hijos existentes.element.before(...)añade hermanos anteriores.element.after(...)añade hermanos posteriores.
Cada uno acepta varios nodos y cadenas. Las cadenas se tratan como texto, por lo que list.append("<li>New</li>") no construye un elemento de lista. Los signos de menor y mayor aparecen como caracteres dentro de la lista.
Los métodos más antiguos siguen apareciendo en el código. appendChild(node) acepta un nodo y lo devuelve; no acepta una cadena. append() devuelve undefined. parent.insertBefore(newNode, referenceNode) inserta un nodo antes de un hijo existente; usar null como referencia añade al final.
Comprende la diferencia entre mover y copiar
Un nodo solo puede ocupar un lugar en el árbol. Insertar un nodo existente lo mueve. En una lista ordenada como a, b, c, list.prepend(list.lastElementChild) mueve c al principio y produce c, a, b. No deja un segundo c al final.
Esto también explica un error habitual en los bucles: crear un <li> fuera de un bucle y añadirlo repetidamente deja un solo elemento. Cada iteración modifica y mueve ese mismo objeto. Crea un elemento nuevo en cada iteración cuando la página necesite varios elementos, o haz clones separados.
Inserta marcado fiable junto al contenido existente
insertAdjacentHTML(position, markup) analiza HTML sin sustituir los hijos existentes. Sus cuatro nombres de posición son "beforebegin" y "afterend" para hermanos fuera del elemento, y "afterbegin" y "beforeend" para hijos dentro de él. list.insertAdjacentHTML("beforeend", "<li>New</li>") añade un elemento analizado. Usa esto solo para marcado fiable; el texto externo debe ir en textContent. insertAdjacentElement() e insertAdjacentText() usan los mismos nombres de posición para un elemento o texto sin formato.
Puntos clave
- Crear, rellenar e insertar son pasos separados.
- append/prepend añaden hijos; before/after añaden hermanos.
- Pasar una cadena a append() inserta texto sin analizar HTML.
- Insertar un nodo existente lo mueve en lugar de copiarlo.
- Crea un elemento nuevo en cada iteración cuando necesites varios objetos.
- appendChild() acepta un nodo y lo devuelve; append() acepta varias entradas y devuelve undefined.
- insertAdjacentHTML() conserva los hijos existentes, pero sigue analizando su entrada como HTML.
5.2 Elimina, sustituye y clona los objetos adecuados
Eliminar un elemento cambia el árbol, pero no borra todas las referencias a ese objeto. Sustituirlo crea una distinción similar: el objeto nuevo ocupa su lugar mientras las variables guardadas pueden seguir refiriéndose al antiguo.
Elimina un elemento o varias coincidencias
element.remove() desconecta ese elemento. parent.removeChild(child) es la forma más antigua basada en el padre y devuelve el nodo eliminado. Si una variable sigue guardando el nodo, el script puede leerlo o volver a insertarlo más adelante.
Para eliminar tareas terminadas, selecciona una colección estática y recórrela:
document.querySelectorAll(".task.done")
.forEach(task => task.remove());
Con cinco tareas, dos marcadas como terminadas, quedan tres. Eliminar un elemento no cambia las referencias que guarda la NodeList estática, por lo que el bucle visita las dos tareas seleccionadas.
No cuentes hacia delante en una lista dinámica que se reduce
list.children es dinámica. Con seis hijos, un bucle que avanza y elimina items[i] elimina solo tres. Después de la primera eliminación, el segundo elemento se desplaza al índice 0, pero i avanza a 1. El siguiente hijo original se omite y el mismo desplazamiento se repite.
Toma una instantánea antes de eliminar todos los hijos actuales:
Array.from(list.children).forEach(item => item.remove());
Para vaciar un contenedor, list.replaceChildren() es más claro. Asignar list.textContent = "" o list.innerHTML = "" también lo vacía. Una cadena vacía no analiza contenido externo.
Sustituye un solo nodo o todo el conjunto de hijos
old.replaceWith(newElement) coloca un nodo nuevo donde estaba el antiguo. Para <p id="status">Loading…</p>, document.querySelector("#status").replaceWith(list) sustituye el mensaje por la lista. parent.replaceChildren(a, b, c) sustituye todos los hijos del padre en una sola operación y conserva el propio padre.
Esta diferencia importa para las referencias guardadas. Una variable que contiene el padre sigue siendo válida después de replaceChildren(), pero las referencias a los hijos eliminados apuntan ahora a objetos desconectados. Sustituir un contenedor con replaceWith() también desconecta ese contenedor.
Copia el elemento con o sin descendientes
element.cloneNode(true) hace una copia profunda, incluidos los descendientes y los atributos. cloneNode() o cloneNode(false) copia el elemento y sus atributos sin sus hijos. Un elemento de lista clonado sin descendientes no tiene el texto del elemento original.
Un clon comienza desconectado y debe insertarse. También hereda el id del original. Dale un id nuevo o elimina ese atributo antes de colocarlo en la misma página, para que la selección por id siga siendo fiable.
Maneja elementos opcionales
Si una búsqueda puede no encontrar nada, no llames inmediatamente a un método en su resultado. document.querySelector("#promo").remove() lanza un error cuando no existe ninguna promoción. document.querySelector("#promo")?.remove() no hace nada en ese caso. Para un contenedor necesario, un resultado ausente es una señal útil para comprobar el selector y el momento de ejecución del script antes de intentar una actualización estructural.
Puntos clave
- remove() desconecta un nodo; una referencia guardada aún puede usarlo o volver a insertarlo.
- Usa una lista estática para eliminar varios elementos seleccionados.
- replaceChildren() conserva el contenedor y sustituye o elimina sus hijos.
- replaceWith() sustituye el propio nodo seleccionado.
- cloneNode(true) copia los descendientes; un clon superficial los omite.
- La clonación copia los id, así que cambia o elimina un id copiado antes de la inserción.
6Convierte datos en una página
Los arrays describen lo que debe mostrar una página; el renderizado convierte esas descripciones en elementos. Empieza con un elemento, amplía el patrón a listas y tablas y después organiza el marcado repetido con fragmentos o plantillas. Una función de renderizado hace previsibles las actualizaciones posteriores cuando cambian los datos. Mantén diferenciados el array original, la vista seleccionada y los elementos mostrados para que el filtrado, la ordenación, los resultados vacíos y los resúmenes sean coherentes.
6.1 Renderiza elementos de un array como entradas de lista y filas de tabla
El renderizado consiste en convertir datos en una estructura DOM visible. Mantén el array como fuente y construye un elemento para cada objeto. Coloca los valores de datos en textContent para que sigan siendo texto incluso si contienen signos de menor y mayor.
Construye un elemento para cada objeto
Usa estos objetos de libros:
const books = [
{ id: 1, title: "Dune", pages: 412 },
{ id: 2, title: "Emma", pages: 474 },
{ id: 3, title: "Beloved", pages: 324 }
];
function createBookItem(book) {
const li = document.createElement("li");
li.dataset.id = String(book.id);
li.textContent = `${book.title} (${book.pages} pages)`;
return li;
}
const list = document.querySelector("#books");
list.append(...books.map(createBookItem));
map() llama a la función constructora una vez por libro y produce tres elementos separados. La propagación pasa esos elementos como argumentos separados a append(). La pantalla muestra «Dune (412 pages)», «Emma (474 pages)» y «Beloved (324 pages)». Los números de páginas suman 1210.
Sin propagación, list.append(books.map(createBookItem)) recibe un solo array. Convierte ese array en texto que contiene cadenas como «[object HTMLLIElement]» en lugar de insertar los elementos de lista.
El id almacenado conecta el elemento mostrado con los datos. Lee Number(li.dataset.id) antes de compararlo con los id numéricos de los libros y después usa books.find(book => book.id === id).
Maneja datos ausentes y vacíos
Si falta un campo de autor opcional, la interpolación directa muestra «undefined». Usa book.author ?? "Unknown author" como alternativa de respaldo cuando el campo sea null o undefined. La coalescencia nula deja sin cambios otros valores, incluidos 0 y una cadena vacía.
Si el array está vacío, muestra un mensaje como «Todavía no hay libros». Un resultado vacío debe indicar al usuario que actualmente no hay elementos. Al volver a renderizar, sustituye la presentación anterior para que un mensaje o unos elementos anteriores no permanezcan junto al nuevo resultado.
Comprende qué hace el método de cadena HTML
Un array fiable puede transformarse en cadenas HTML y unirse con join("") antes de asignarlo a innerHTML. La unión elimina las comas que, de otro modo, insertaría la conversión del array a cadena. Este método analiza cada valor interpolado como HTML. Usa el método de construcción de elementos cuando los valores puedan proceder de fuentes externas.
Construye una estructura de tabla válida
Para datos de tabla, construye un <tr> por objeto y un <td> por cada campo mostrado. Añade las filas al <tbody> de la tabla. Para mediciones de Oslo a 4,25 °C y El Cairo a 28,5 °C, la celda de temperatura puede usar reading.temp.toFixed(1): muestra «4.3» y «28.5». toFixed() devuelve una cadena con las posiciones decimales solicitadas. En cambio, toLocaleString() da formato según la configuración regional del usuario, que puede usar una coma decimal. Mantén el formato en el paso de presentación para que los datos numéricos sigan disponibles para los cálculos.
Construye ambas celdas antes de insertar la fila
Para un cuerpo de tabla vacío existente llamado tbody, esto renderiza las mediciones:
const readings = [{ city: "Oslo", temp: 4.25 }, { city: "Cairo", temp: 28.5 }];
const rows = readings.map(reading => {
const row = document.createElement("tr");
const city = document.createElement("td");
const temperature = document.createElement("td");
city.textContent = reading.city;
temperature.textContent = reading.temp.toFixed(1) + " °C";
row.append(city, temperature);
return row;
});
tbody.replaceChildren(...rows);
Cada iteración crea una fila nueva y dos celdas nuevas. Rellenar ambas celdas antes de añadir la fila deja explícito el orden de los campos. La propagación de rows proporciona los dos nodos de fila por separado; la sustitución final también elimina las filas anteriores.
Puntos clave
- Construye un elemento separado para cada objeto de datos y rellena los valores con textContent.
- Propaga un array de nodos al pasarlos a append().
- Usa atributos de datos para conectar los elementos mostrados con los objetos.
- Proporciona mensajes para el estado sin datos y alternativas de respaldo para valores nulos o indefinidos.
- Coloca las filas de tabla en tbody y los campos en celdas.
- toFixed() devuelve texto para mostrar; conserva los datos numéricos para los cálculos.
6.2 Construye contenido repetido antes de insertarlo
Cuando una lista contiene muchos elementos, construye el contenido nuevo fuera de la página e insértalo conjuntamente. Un fragmento de documento (DocumentFragment) agrupa nodos sin añadir un elemento contenedor. Una plantilla te permite escribir una estructura repetida en HTML y rellenar una copia nueva para cada objeto.
Reúne nodos en un fragmento
const fragment = document.createDocumentFragment();
for (const book of books) {
fragment.append(createBookItem(book));
}
list.append(fragment);
El fragmento comienza fuera del documento. Cada elemento nuevo se convierte en su hijo. Añadir el fragmento mueve sus hijos a la lista en el orden que ya tienen; no inserta el propio fragmento como contenedor. Después de transferir 100 elementos a una lista vacía, la lista tiene 100 hijos y el fragmento tiene 0.
Este patrón agrupa la inserción y mantiene organizado el código de construcción. No garantiza una mejora concreta de velocidad. También sirve un array de nodos construidos: list.append(...items) los añade, mientras que list.replaceChildren(...items) sustituye el contenido actual por ellos.
Define marcado repetido en una plantilla
<template id="book-row">
<li class="book"><span class="title"></span>
(<span class="pages"></span> pages)</li>
</template>
El navegador analiza este marcado sin mostrarlo. El contenido se encuentra en un DocumentFragment separado en template.content. Una búsqueda a nivel de documento no busca dentro de ese fragmento. Selecciona la plantilla, clona su contenido y después busca dentro del clon:
const template = document.querySelector("#book-row");
const clone = template.content.cloneNode(true);
clone.querySelector(".title").textContent = book.title;
clone.querySelector(".pages").textContent = book.pages;
const item = clone.firstElementChild;
list.append(clone);
El título y el número de páginas se rellenan antes de la inserción. item guarda una referencia al nuevo <li>. Después de añadirlo, clone está vacío porque sus hijos se han movido, pero item sigue refiriéndose al elemento insertado.
Conserva la fuente reutilizable
Añade una copia cada vez. Llamar a list.append(template.content) saca los nodos originales de la plantilla. Una búsqueda posterior dentro de template.content devuelve entonces null y el siguiente intento de rellenar el título ausente lanza un error. La plantilla original debe seguir disponible para libros posteriores.
Para muchas copias, rellena cada fragmento clonado, añade esas copias a un fragmento de recopilación y después inserta la colección. Un fragmento puede recibir los hijos de otro fragmento igual que una lista.
Elige un método de construcción legible
createElement() es adecuado para una estructura pequeña o que varía considerablemente según el elemento. Una plantilla es adecuada para marcado repetido más grande que resulta más fácil editar como HTML. En ambos casos, inserta los valores externos como texto. Una cadena HTML es adecuada para marcado fiable, pero la interpolación en ella sigue provocando el análisis de HTML. Elige el método de construcción según la estructura que necesites mantener, conservando el mismo orden: crear o clonar, rellenar e insertar.
Reúne copias rellenadas para una sola sustitución
Con la plantilla de libros anterior y un array books existente:
const group = document.createDocumentFragment();
for (const book of books) {
const copy = template.content.cloneNode(true);
copy.querySelector(".title").textContent = book.title;
copy.querySelector(".pages").textContent = book.pages;
group.append(copy);
}
list.replaceChildren(group);
Cada copia rellenada transfiere su elemento a group. La última línea sustituye el contenido de la lista por esos elementos y vacía group. La plantilla original permanece intacta durante todo el proceso, por lo que la función puede repetir la construcción para un array posterior.
Puntos clave
- Añadir un fragmento mueve sus hijos y deja el fragmento vacío.
- Un fragmento agrupa nodos sin crear un contenedor en la página.
- El contenido de las plantillas se analiza, pero permanece fuera del árbol del documento mostrado.
- Clona template.content para cada elemento y rellénalo antes de insertarlo.
- Guarda la referencia al elemento antes de que se vacíe el fragmento que lo contiene.
6.3 Mantén las vistas renderizadas sincronizadas con los datos
Usa los datos como única fuente de verdad. Una función de renderizado deriva una presentación del array actual. Llámala después de modificar el array o uno de sus objetos.
Sustituye la presentación en cada renderizado
Supón que tasks contiene cuatro objetos, exactamente uno terminado, y que la tarea 2 existe y no está terminada. Una función de renderizado puede construir elementos nuevos y un resumen:
function render() {
const items = tasks.map(task => {
const li = document.createElement("li");
li.dataset.id = String(task.id);
li.textContent = task.text;
li.classList.toggle("done", task.done);
return li;
});
list.replaceChildren(...items);
const doneCount = tasks.filter(task => task.done).length;
summary.textContent = `${doneCount} of ${tasks.length} done`;
}
Después de tasks.push({ id: 5, text: "Book dentist", done: false }); render();, la lista tiene cinco elementos y el resumen dice «1 of 5 done». Ejecutar tasks.find(task => task.id === 2).done = true; render(); lo cambia a «2 of 5 done».
Sustituir los hijos es esencial aquí. Si la función solo añadiera todos los elementos, llamarla dos veces duplicaría la presentación. Eliminar solo un elemento DOM también es temporal: si su objeto permanece en el array, el renderizado lo devuelve. Con tasks declarado mediante let, elimina de los datos con tasks = tasks.filter(task => task.id !== id) y vuelve a renderizar.
Deriva una vista sin perder la fuente
Para una función de renderizado que acepta un array de vista, pasa tasks.filter(task => !task.done) para mostrar solo las tareas sin terminar. Conserva el array completo para vistas posteriores y recuentos de toda la lista. Da significados claros a los resúmenes: un recuento de tareas visibles es diferente de un recuento de todas las tareas.
sort() modifica el array sobre el que se llama. Ordena una copia para mostrarla con [...tasks].sort(...), o usa tasks.toSorted(...) para obtener una copia ordenada. Proporciona un comparador: los valores numéricos necesitan (a, b) => a - b, y los títulos pueden usar (a, b) => a.title.localeCompare(b.title). La ordenación predeterminada compara las formas de cadena, por lo que [100, 25, 3].sort() permanece en ese orden; la ordenación numérica da [3, 25, 100].
Relaciona los id y analiza los datos correctamente
Un dataset.id mostrado es una cadena. Conviértelo antes de compararlo de forma estricta con id numéricos, o find() puede devolver undefined aunque exista el objeto buscado. Los datos JSON son diferentes: JSON.parse() conserva los números y booleanos de JSON con esos tipos. Los objetos analizados pueden pasar por la misma función de renderizado que los objetos escritos directamente en el código.
Conserva el estado local cuando sea necesario
Una reconstrucción completa crea elementos nuevos. Puede perder el foco y el texto escrito en campos de entrada dentro de la zona reconstruida. Para un cambio pequeño de estado que deba conservar esos objetos, actualiza los datos y después actualiza el elemento existente, por ejemplo con li.classList.toggle("done", task.done). Los datos deben seguir registrando el cambio para que un renderizado completo posterior coincida con la presentación actual.
Da entradas separadas a la vista y al resumen
Una vista filtrada puede seguir mostrando un resumen de todas las tareas:
function renderOpenTasks() {
const visible = tasks.filter(task => !task.done);
const nodes = visible.map(task => {
const li = document.createElement("li");
li.textContent = task.text;
return li;
});
if (visible.length === 0) {
const empty = document.createElement("li");
empty.textContent = "No open tasks";
nodes.push(empty);
}
list.replaceChildren(...nodes);
const done = tasks.filter(task => task.done).length;
summary.textContent = `${done} of ${tasks.length} done`;
}
Un array con todas las tareas terminadas muestra el mensaje de estado sin datos para esta vista, pero conserva todos los objetos para el total. Contar a partir de visible respondería a otra pregunta y podría indicar que no hay tareas terminadas simplemente porque esta vista las excluye.
Puntos clave
- Actualiza los datos y después deriva la página de esos datos.
- Sustituye los hijos anteriores al reconstruir una lista para evitar duplicados.
- Filtra y ordena una vista derivada mientras conservas el array original cuando sea necesario.
- Proporciona un comparador para la ordenación numérica y convierte los id de dataset antes de compararlos con números.
- JSON.parse() conserva los tipos de datos numérico y booleano.
- Usa una actualización selectiva de un elemento cuando la reconstrucción haría perder el foco o un estado de entrada necesario.
Ejemplos de DOM en JavaScript
1Oriéntate en el árbol de una página
11 pasos
- 1IntroducciónEmpieza con una página que puedas inspeccionar
El navegador construye objetos a partir del HTML. JavaScript trabaja con este árbol DOM.
Sigue una lista de dos elementos desde el marcado hasta los nodos y después usa las relaciones familiares para llegar a un elemento cercano. Mantén abiertas las herramientas de desarrollo para comparar la página visible con su árbol.
- 2ExplicaciónEntra a través de document
El DOM es el modelo dinámico de la página que mantiene el navegador.
documentproporciona acceso;document.bodyse refiere al elemento body.El navegador proporciona esta API. JavaScript la llama para modificar la página actual sin recargarla ni reescribir el archivo HTML del servidor.
- 3EjemploObserva el elemento y su texto por separado
Observa
<li>Buy milk</li>. El<li>se convierte en un nodo de elemento y «Buy milk» se convierte en un nodo de texto hijo dentro de él.Lee
nodeTypepara distinguirlos: el elemento es de tipo 1 y su hijo de texto es de tipo 3. Los comentarios son de tipo 8 y el propio documento es de tipo 9. «Nodo» nombra el grupo más amplio; un elemento es un tipo de nodo. - 4EjemploCuenta lo que añade la sangría
Usa exactamente esta disposición:
<ul id="tasks"> <li>Buy milk</li> <li>Call Sam</li> </ul>La lista tiene dos hijos de tipo elemento. También tiene tres nodos de texto con espacios en blanco: antes, entre y después de esos elementos. Por tanto, su
children.lengthes 2, mientras quechildNodes.lengthes 5. Los nodos adicionales proceden de los caracteres entre etiquetas. - 5DesafíoPredice el primer nodo
En la lista sangrada de la diapositiva anterior, ¿qué tipo de nodo es
tasks.firstChildy por qué es diferente detasks.firstElementChild?---reveal---
firstChildes el nodo de texto con espacios en blanco anterior al primer elemento.firstElementChildomite ese nodo y devuelve el primer<li>. La sangría afecta a la secuencia de nodos aunque no cree otra tarea visible. - 6ConsejoInspecciona el árbol actual
Elige «Inspeccionar» en el primer elemento de lista. El panel Elementos muestra el DOM actual. Con el elemento seleccionado,
$0en la consola se refiere a él yconsole.dir($0)muestra sus propiedades.El árbol puede incluir elementos añadidos por el analizador, como un
<tbody>alrededor de las filas de una tabla. Usa este panel para comprobar el anidamiento real en lugar de suponer que coincide con todos los límites de etiquetas del código fuente. - 7EjemploPasa al siguiente elemento
Guarda la lista como
tasksy después sigue una relación entre elementos:const first = tasks.firstElementChild; const second = first.nextElementSibling;second.textContentes «Call Sam». Leerfirst.nextSiblingen su lugar llega al espacio en blanco entre los elementos. Elige la forma para elementos cuando la tarea sea desplazarte entre elementos de la página y deban omitirse los nodos de texto. - 8ExplicaciónDetente de forma segura en el último elemento
El
nextElementSiblingdel último elemento esnull. Leer una propiedad directamente de esa referencia ausente lanza un error de tipo.second.nextElementSibling?.textContentse detiene ahí y daundefined, sin añadir un nodo ni proporcionar una cadena vacía. - 9ConexiónEncuentra el elemento contenedor por su significado
Un span anidado puede encontrar la tarea que lo contiene con
span.closest("li"). La búsqueda comienza en el propio span y después comprueba antecesores sucesivos hasta encontrar una coincidencia.span.matches("li")solo comprueba el span y devuelve falso en este caso. Una búsqueda de antecesores es útil cuando un contenedor adicional podría hacer que un número fijo de saltos entre padres lleve al lugar equivocado. - 10DesafíoNavega a través de un contenedor añadido
Cada elemento de la lista ahora encierra su texto en un span. Partiendo del primer span, ¿cómo puedes leer el texto del siguiente elemento sin depender de los nodos de espacios en blanco ni del número de contenedores dentro de un elemento?
---reveal---
Encuentra el elemento que lo contiene y después su siguiente hermano de tipo elemento:
span.closest("li").nextElementSibling?.textContent. El elemento contenedor se encuentra por su etiqueta y la navegación exclusiva entre hermanos de tipo elemento omite los espacios en blanco entre elementos. - 11RepasoPrueba después con una tabla
Inspecciona una tabla cuyo código fuente coloca una fila directamente dentro de
<table>. Encuentra el padre real de la fila.Compara sus recuentos de nodos hijos y de hijos de tipo elemento, usando el panel Elementos para explicar la estructura añadida por el analizador y los espacios en blanco.
2Selecciona y actualiza los elementos previstos
12 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónElige una búsqueda antes de modificar una página
- 2ExplicaciónUsa la sintaxis de id adecuada para el método
- 3EjemploMantén una clase repetida dentro de su tarjeta
- 4ConsejoDistingue un nodo ausente de una sintaxis incorrecta
- 5DesafíoExplica un resultado null prematuro
- 6EjemploRecorre los elementos devueltos
- 7ExplicaciónConvierte cuando necesites métodos de array
- 8EjemploCompara dos colecciones guardadas
- 9Idea claveObserva una colección dinámica que se reduce
- 10DesafíoElige el selector combinado adecuado
- 11DesafíoCombina el ámbito con una iteración segura
- 12RepasoDiagnostica tu próxima búsqueda fallida
3Actualiza un perfil y lee los valores de su formulario
15 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónSepara la información que contiene un elemento
- 2EjemploLee texto sin sus etiquetas
- 3ExplicaciónTrata los valores externos como caracteres
- 4DesafíoConserva un campo de entrada existente
- 5ConexiónLee el texto renderizado cuando sea necesario
- 6EjemploLee una URL escrita o una URL resuelta
- 7ExplicaciónEstablece un booleano mediante su presencia
- 8DesafíoCorrige un control deshabilitado
- 9EjemploConvierte un nombre de datos en un nombre de propiedad
- 10ExplicaciónLee el contenido actual de un campo
- 11DesafíoCalcula con el valor de un campo
- 12EjemploEncuentra un objeto mediante un id mostrado
- 13ConsejoDa un nombre legible a un control con icono
- 14DesafíoConecta la búsqueda de datos con una presentación segura
- 15RepasoInspecciona un campo antes y después de editarlo
4Haz que la apariencia siga un estado claro
13 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónDeja que los datos elijan el estado visible
- 2EjemploConserva una clase base al añadir un estado
- 3ExplicaciónUsa una condición para actualizaciones repetidas
- 4DesafíoPredice dos actualizaciones repetidas
- 5EjemploCalcula un porcentaje CSS
- 6ExplicaciónLee el resultado de la cascada
- 7DesafíoRestaura el color de la hoja de estilos
- 8ExplicaciónElige qué elimina un panel cerrado
- 9EjemploHaz que un panel y su control coincidan
- 10ConsejoComprueba un estilo que anula hidden
- 11DesafíoDiagnostica un control invisible pero activo
- 12DesafíoCombina clases con un valor calculado
- 13RepasoComprueba el estado y la apariencia por separado
5Construye elementos y sigue sus referencias a objetos
12 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónConstruye una tarea en etapas separadas
- 2EjemploCrea un elemento desconectado
- 3EjemploInserta el elemento terminado
- 4ExplicaciónElige entre hijos o hermanos
- 5EjemploMueve un nodo que ya existe
- 6DesafíoExplica un bucle que produce un solo elemento
- 7ExplicaciónDesconecta sin destruir una referencia
- 8EjemploSustituye un elemento o toda una presentación
- 9ConsejoCopia descendientes y comprueba los id
- 10DesafíoPredice una copia superficial
- 11DesafíoMueve el original e inserta una copia
- 12RepasoSigue las identidades junto con el marcado
6Renderiza una lista a partir de datos y actualízala de forma fiable
17 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónHaz que el array determine la presentación
- 2EjemploEscribe una función constructora para un libro
- 3EjemploPropaga el array como argumentos de nodos
- 4ConsejoMantén legibles los datos ausentes
- 5ConexiónAplica el patrón a filas de tabla
- 6DesafíoAverigua por qué la lista muestra texto de objetos
- 7EjemploReúne nodos fuera de la página
- 8ExplicaciónMantén la estructura repetida en HTML
- 9EjemploRellena el clon antes de transferirlo
- 10DesafíoConserva la plantilla reutilizable
- 11ExplicaciónSustituye la presentación a partir de los datos actuales
- 12EjemploActualiza un objeto y su resumen
- 13ExplicaciónMantén separada una vista ordenada
- 14DesafíoExplica un elemento que vuelve tras eliminarlo
- 15Idea claveConserva el estado local de entrada
- 16DesafíoCombina una búsqueda con una actualización selectiva
- 17RepasoComprueba el renderizado en tres estados
Ejercicios de DOM en JavaScript
Set 1: Lee y modifica una página10 Preguntas de Práctica
Pregunta 1 de 10
button.setAttribute("disabled", "false"). ¿Qué estado indica button.disabled?Mostrar respuestaOcultar respuesta
button.disabled es verdadero. Su texto «false» no puede desactivar un atributo booleano; elimínalo o establece la propiedad booleana en falso para habilitar el botón.Pregunta 2 de 10
input.value + 2?Mostrar respuestaOcultar respuesta
+ 2 la une y produce «62». Convierte antes de sumar con Number(input.value) + 2 para obtener el número 8, incluso cuando el campo sea de tipo numérico.Pregunta 3 de 10
Mostrar respuestaOcultar respuesta
Pregunta 4 de 10
<ul><li>A</li> <li>B</li></ul>, una variable first contiene el primer elemento. ¿Qué devuelve first.nextSibling.nodeType?Mostrar respuestaOcultar respuesta
nextElementSibling. La navegación por nodos incluye el texto entre etiquetas; la navegación por elementos lo omite.Pregunta 5 de 10
<section id="report"> con getElementById()?Mostrar respuestaOcultar respuesta
getElementById(). La almohadilla pertenece a la sintaxis de selectores CSS; pasar «#report» aquí busca un id que contiene ese carácter y no encuentra esta sección.Pregunta 6 de 10
flag. El código guarda const live = box.getElementsByClassName("flag") y después ejecuta for (let i = 0; i < live.length; i++) { live[i].classList.remove("flag"); }. ¿Qué elementos conservan la clase?Mostrar respuestaOcultar respuesta
Pregunta 7 de 10
label.textContent = "<em>Saved</em>"?Mostrar respuestaOcultar respuesta
textContent inserta los caracteres literales «Saved». No analiza esas etiquetas para crear un elemento de énfasis; usa la creación de elementos o el análisis de HTML fiable cuando quieras crear una estructura.Pregunta 8 de 10
class="card compact". ¿Cómo puede el código añadir «selected» y conservar ambas clases existentes?Mostrar respuestaOcultar respuesta
classList.add("selected") conserva «card» y «compact». Asignar toda la cadena de clases las sustituye, mientras que un punto inicial pasaría a formar parte del nombre añadido en lugar de actuar como sintaxis de selector.Pregunta 9 de 10
list.append(list.firstElementChild)?Mostrar respuestaOcultar respuesta
Pregunta 10 de 10
makeItem() devuelve un <li> nuevo. ¿Qué inserta list.append(records.map(makeItem)) cuando records tiene dos entradas?Mostrar respuestaOcultar respuesta
map() devuelve un array y append() recibe ese array como un solo argumento. Lo convierte en texto que contiene las representaciones de cadena de los elementos en lugar de insertar los nodos. Usa list.append(...records.map(makeItem)) para pasar cada elemento como argumento separado.Set 2: Elige la operación DOM adecuada10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
score: 0. ¿Qué muestra record.score ?? "Pending" cuando se asigna a textContent?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
<table><tr><td>8</td></tr></table>. ¿Qué elemento hijo directo coloca normalmente el analizador dentro de la tabla?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
<head> selecciona un pie de página escrito más adelante en <body> y obtiene null. El selector es correcto. ¿Qué atributo de script hace que se ejecute después del análisis del HTML?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
.note. Uno pierde su clase note y se añade un nuevo elemento note. ¿Cuál es la longitud de la NodeList guardada?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
data-record-id="38". ¿Cómo puede el código comparar ese id con el número 38 mediante igualdad estricta?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
container.replaceChildren(), asigna a.textContent = "C" y después ejecuta container.append(a) y container.append(a.cloneNode(true)). ¿Qué contiene el contenedor?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
[{n: 14}, {n: 3}, {n: 9}]. Una vista debe mostrar el orden numérico ascendente y conservar el orden de origen. ¿Qué expresión construye esa vista?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 3: Sigue nodos, estados y colecciones10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
entry y está dentro de una sección con esa misma clase. ¿Qué devuelve button.closest(".entry")?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
.mark. El código guarda una colección dinámica por clase y una NodeList estática de coincidencias. Elimina el primer miembro de la colección dinámica y después elimina la clase del nuevo primer miembro. ¿Cuáles son las longitudes finales de la colección dinámica y de la estática?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
https://example.com/catalog/, un enlace está escrito como <a href="/guide">Guide</a>. ¿Qué devuelve link.getAttribute("href")?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
class="row done". El código ejecuta row.classList.toggle("done", false) dos veces. ¿Qué clases permanecen?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
insertAdjacentHTML() insertar una nota fiable como primer hijo de la sección?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
template.content directamente a una lista. ¿Por qué una llamada posterior a template.content.querySelector(".title") devuelve null?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
[{id:31, done:true}, {id:32, done:false}, {id:33, done:false}]. El código elimina solo la fila 31 del DOM, marca como terminada la tarea 32 en el array y después reconstruye por completo todas las filas y el resumen a partir de ese array. ¿Qué se muestra?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 4: Construye presentaciones fiables basadas en datos10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
Hello, un <strong>team</strong> anidado y un comentario HTML. ¿Es el texto del elemento strong hermano del comentario?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
.status. Una variable main contiene la sección principal. ¿Qué búsqueda encuentra su primer descendiente status?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
const field = box.querySelector("input"). Un usuario cambia ese campo de entrada de «A» a «B». El script ejecuta box.innerHTML += "<span>Done</span>" y después field.value = "C". ¿Qué ocurre con el campo visible?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
value="2". Después de que el usuario lo cambie a 7, un script lee Number(input.getAttribute("value")) + 1. ¿Qué número obtiene?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
panel.hidden = true, pero el CSS contiene .panel { display: grid; } y el panel permanece visible. Su control también sigue indicando aria-expanded="true". ¿Qué corrige ambos estados para un panel cerrado?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
a, ejecuta list.lastElementChild.before(a) y después list.prepend(list.lastElementChild). ¿Cuál es el orden final?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
author. ¿Qué asignación muestra «Unknown author» sin analizar el valor como HTML?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
clone.querySelector(".name").textContent = record.name. ¿Por qué falla?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
<li> del id 12 y después renderiza una vista filtrada a partir del array sin modificar. El filtro conserva los tres objetos. ¿Qué debe cambiar para que el id 12 siga eliminado después de cualquier renderizado completo posterior?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
[{"id":24,"done":false}]. Después de JSON.parse(), ¿cómo se comparan los tipos de id y done con el data-id="24" de un elemento?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 5: Depura actualizaciones en el DOM10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
<div class="card"><div class="body"><span class="label">A</span></div></div>. Desde la etiqueta, el código usa parentElement.parentElement para encontrar la tarjeta. Se inserta un nuevo contenedor entre body y label. ¿Qué alternativa sigue siendo fiable?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
snap = list.querySelectorAll(".new"). Se añaden dos elementos con la clase new y después un bucle sobre snap elimina la clase new. Una nueva búsqueda por clase se guarda como colección dinámica. ¿Cuáles son snap.length y la longitud de la colección dinámica?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
<script>. ¿Qué actualización conserva el elemento de vista previa e inserta el comentario como texto literal sin analizar HTML?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
class="row selected". Los datos indican que selected es falso. El código ejecuta row.classList.toggle("selected") y más tarde ejecuta row.classList.toggle("selected", false). ¿Cuáles son los dos valores de retorno y las clases finales?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
const open = panel.hidden, asigna panel.hidden = !open y escribe String(open) en aria-expanded. ¿Cuáles son los estados finales?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
<li id="copy-me"><span>Map</span></li> se copia con cloneNode(false). ¿Qué contiene el clon desconectado?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
list.replaceChildren(fragment). ¿Qué objetos siguen teniendo contenido?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
{id: 5, done: false}. Su fila existente tiene data-id="5" y un campo de entrada con foco. El código debe marcar el registro como terminado, reflejarlo en la clase y conservar el objeto del campo. ¿Qué secuencia es adecuada?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
¿Te atascas con una pregunta tuya? Ayuda con Tareas
Términos Clave
A
Actualización selectiva
Alternancia de clase con estado forzado
row.classList.toggle("done", task.done) mantiene la fila coherente en renderizados repetidos.Análisis sintáctico
<tbody>.Atributo
getAttribute() y setAttribute().href de un enlace puede contener «/help» mientras que su propiedad proporciona una URL completa resuelta.Atributo ARIA
aria-label en «Close dialog» proporciona un nombre accesible a un botón que solo contiene un icono.Atributo aria-expanded
aria-expanded="true".Atributo booleano
setAttribute("disabled", "false") porque el atributo existe.Atributo de datos
data- y almacena información para los scripts sin mostrarla como texto.data-id="26" puede relacionarse con el objeto que proporcionó sus campos mostrados.Atributo defer
C
Clonación profunda
Coalescencia nula
?? solo cuando el valor de la izquierda es null o undefined, y deja los demás valores sin cambios.book.author ?? "Unknown author" proporciona texto legible cuando falta el autor opcional.Colección de elementos HTML
list.children.Colección de nodos
querySelectorAll() contiene los elementos coincidentes.Array.from() antes de usar el método de array map().Colección dinámica
Colección estática
querySelectorAll() no incluye un cuarto elemento añadido después de la búsqueda original.Comparador
(a, b) => a - b ordena los valores numéricos de menor a mayor.Contenido de la plantilla
template.content, que contiene la estructura de hijos no mostrada de la plantilla.Conversión de tipos
Number(row.dataset.id) permite que la igualdad estricta compare los dígitos almacenados con un id numérico de objeto.Cuerpo de tabla
<tbody> que agrupa las filas de datos de una tabla.<tr> al cuerpo seleccionado y rellena sus campos en celdas <td>.D
Declaración display: none
Declaración opacity: 0
Declaración visibility: hidden
E
Elemento
<ul> puede contener dos hijos de tipo elemento <li>, así como nodos de texto con espacios en blanco.Elemento de plantilla
Estado sin datos
Estilo calculado
getComputedStyle(title).color puede indicar rojo incluso cuando title.style.color está vacío.Estilo en línea
bar.style.width = "60%" almacena una anchura de progreso calculada directamente en la barra.F
Fragmento de documento
Fuente de verdad
Función de renderizado
H
Herramientas de desarrollo
$0 en la consola.I
Inserción en bloque
replaceChildren(...items).M
Método append()
item.append(title, button) reúne dos elementos hijos dentro de un elemento antes de insertarlo en la página.Método Array.from()
Array.from(list.children) permite que un bucle de eliminación visite todos los hijos originales sin desplazamientos de índices.Método closest()
closest(".product") para encontrar la tarjeta que lo contiene.Método createElement()
document.createElement("li") crea un elemento de lista, pero todavía no lo añade a la lista visible.Método getElementById()
document.getElementById("result") busca el id «result», sin almohadilla inicial.Método insertAdjacentHTML()
Método insertBefore()
list.insertBefore(newItem, list.firstElementChild) coloca el elemento antes del primer hijo de tipo elemento.Método prepend()
Método querySelector()
null si ninguno coincide..name repetida en otro lugar se convierta en el resultado.Método replaceChildren()
Método replaceWith()
Método toFixed()
toFixed(1) antes de insertarla en una celda.Modelo de objetos del documento
N
Nodo
Nodo antecesor
Nodo de texto
Nodo desconectado
Nodo hermano
Nodo hijo
Nodo padre
<ul><li>Read</li></ul>, la lista es el padre inmediato del elemento de lista.Nombre de clase
classList.add() para que ninguno de los nombres contenga un espacio.Notación camelCase
backgroundColor.background-color se escribe como style.backgroundColor en JavaScript.O
Ordenación in situ
[...items] antes de llamar a sort() cuando el orden de origen deba permanecer sin cambios.P
Propiedad
disabled devuelve un booleano, mientras que la lectura de un atributo devuelve una cadena o null.Propiedad checked
checked pasa a ser false.Propiedad classList
classList conserva la clase «card» existente y su estilo base.Propiedad className
className de una tarjeta elimina su clase «card» anterior, salvo que se incluya de nuevo.Propiedad dataset
row.dataset.recordId = "26" crea o modifica el atributo data-record-id.Propiedad hidden
panel.hidden = false para mostrar un panel oculto sin reconstruir su contenido.Propiedad innerHTML
"<strong>Ready</strong>" crea un nuevo elemento strong dentro del contenedor.Propiedad innerText
innerText de una etiqueta visible omite una nota anidada con el estilo display: none.Propiedad outerHTML
Propiedad personalizada de CSS
var()."--accent" mediante style.setProperty() para cambiar las reglas que hacen referencia al valor de acento.Propiedad textContent
Propiedad value
R
Renderizado
S
Secuencias de comandos entre sitios
textContent para un nombre enviado evita que sus caracteres se conviertan en marcado inyectado.Selector CSS
"#profile .name" encuentra descendientes con la clase name del elemento de perfil.Sintaxis de propagación
list.append(...items) inserta cada nodo construido en lugar de la representación de cadena del array.U
Unidad CSS
V
Valor nulo
Vista derivada
tasks.filter(task => !task.done) sin descartar las terminadas.Sobre esta unidad
Crea tus propios Materiales de Estudio
Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.