JavaScript
Tutorial JavaScript: Introducción al DOM
DOM: Descubre cómo el Document Object Model permite interactuar y manipular elementos HTML con JavaScript. Aprende a optimizar tu código.
Aprende JavaScript y certifícateConceptos fundamentales: El DOM como interfaz de programación entre HTML y JavaScript
El Document Object Model (DOM) constituye el puente fundamental entre el código HTML que estructura una página web y el JavaScript que le otorga interactividad. En esencia, el DOM es una representación estructurada del documento HTML que permite a los programas acceder y modificar dinámicamente el contenido, estructura y estilo de una página web.
Cuando un navegador carga una página web, no solo interpreta el HTML para mostrar su contenido, sino que también crea una representación en memoria de ese documento en forma de árbol de objetos. Esta transformación convierte cada elemento HTML (como párrafos, divisiones, encabezados) en nodos manipulables mediante código JavaScript.
Del HTML al DOM: Una transformación visual
Para entender mejor cómo el navegador convierte HTML en una estructura DOM, observemos un ejemplo:
<!-- Código HTML -->
<article>
<h1>Introducción al DOM</h1>
<p>El DOM permite <em>manipular</em> páginas web.</p>
</article>
Este HTML se transforma en la siguiente estructura de árbol DOM:
document
└── article (ElementNode)
├── h1 (ElementNode)
│ └── "Introducción al DOM" (TextNode)
└── p (ElementNode)
├── "El DOM permite " (TextNode)
├── em (ElementNode)
│ └── "manipular" (TextNode)
└── " páginas web." (TextNode)
Como puedes ver, cada etiqueta HTML se convierte en un nodo de elemento en el árbol DOM, y el texto se convierte en nodos de texto. Esta estructura jerárquica permite a JavaScript navegar y manipular cualquier parte del documento.
El DOM como una interfaz orientada a objetos
Una característica fundamental del DOM es que implementa un paradigma orientado a objetos. Esto significa que:
- Cada elemento del DOM es un objeto JavaScript con propiedades y métodos
- Estos objetos se organizan en una jerarquía de clases con herencia
- Existe una relación de "es un" entre los diferentes tipos de nodos
Por ejemplo, un elemento <div>
en el DOM es una instancia de HTMLDivElement
, que hereda de HTMLElement
, que a su vez hereda de Element
, y finalmente de Node
:
const div = document.querySelector('div');
console.log(div instanceof HTMLDivElement); // true
console.log(div instanceof HTMLElement); // true
console.log(div instanceof Element); // true
console.log(div instanceof Node); // true
Esta jerarquía de herencia, que ya estudiamos en lecciones anteriores sobre POO, permite que cada elemento tenga propiedades y métodos específicos según su tipo, pero también comparta funcionalidades comunes con otros elementos.
Función del DOM como interfaz
El DOM actúa como una API (Application Programming Interface) que establece un conjunto de reglas y métodos estandarizados para que JavaScript pueda:
- Acceder a cualquier elemento de la página
- Modificar el contenido de los elementos
- Alterar los atributos y estilos
- Crear nuevos elementos
- Eliminar elementos existentes
- Responder a eventos del usuario
Esta interfaz permite que el código JavaScript no necesite entender HTML directamente, sino que trabaje con una abstracción orientada a objetos del documento.
// Ejemplo básico de interacción con el DOM
const heading = document.createElement('h1');
heading.textContent = 'Hola Mundo DOM!';
document.body.appendChild(heading);
En este ejemplo, no estamos manipulando texto HTML directamente, sino utilizando objetos y métodos del DOM para crear y añadir un nuevo elemento a la página.
El DOM y el rendimiento
La manipulación del DOM es una operación costosa en términos de rendimiento. Cada vez que se modifica el DOM, el navegador debe recalcular la disposición de los elementos (reflow) y volver a pintar la pantalla (repaint).
// Enfoque ineficiente (múltiples manipulaciones del DOM)
for (let i = 0; i < 100; i++) {
const paragraph = document.createElement('p');
paragraph.textContent = `Paragraph ${i}`;
document.body.appendChild(paragraph); // Causa reflow en cada iteración
}
// Enfoque optimizado (manipulación única del DOM)
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const paragraph = document.createElement('p');
paragraph.textContent = `Paragraph ${i}`;
fragment.appendChild(paragraph);
}
document.body.appendChild(fragment); // Un solo reflow al final
Esta característica ha llevado al desarrollo de bibliotecas y frameworks como React, Vue o Angular, que implementan DOM virtuales o sistemas de renderizado optimizados para minimizar las manipulaciones directas del DOM.
El DOM vs. HTML
Es crucial entender que el DOM no es exactamente igual al código HTML original. El DOM:
- Corrige automáticamente errores en el HTML
- Añade elementos implícitos que pueden omitirse en HTML (como
<tbody>
en tablas) - Representa el estado actual de la página, que puede haber cambiado desde la carga inicial
// HTML original: <div></div>
// El DOM corrige automáticamente y representa:
console.log(document.querySelector('div').outerHTML); // <div></div>
// HTML original con error: <p>Texto<p>
// El DOM corrige y representa:
// <p>Texto</p><p></p>
Esta capacidad de representar y corregir el documento HTML es fundamental para entender cómo JavaScript interactúa con las páginas web a través del DOM.
Anatomía del árbol de nodos: Tipos de nodos y estructura jerárquica del documento
El DOM representa un documento HTML como una estructura de árbol donde cada parte del documento se convierte en un nodo. Esta organización jerárquica permite navegar eficientemente por el documento y manipular sus elementos de forma precisa.
Estructura jerárquica del DOM
Cuando un navegador procesa un documento HTML, construye una representación en memoria organizada como un árbol invertido. En la cima de esta estructura se encuentra el nodo document
, que actúa como raíz de todo el árbol. A partir de ahí, se ramifica siguiendo la estructura anidada del HTML original.
Tomemos un HTML más completo y veamos su representación DOM:
<!DOCTYPE html>
<html>
<head>
<title>Mi Página</title>
<meta charset="utf-8">
</head>
<body>
<header>
<h1>Bienvenidos</h1>
</header>
<main>
<p>Este es un <a href="#">enlace</a> de ejemplo.</p>
</main>
</body>
</html>
Su representación en el árbol DOM sería:
document
├── DOCTYPE html
└── html (elemento raíz)
├── head
│ ├── title
│ │ └── "Mi Página" (texto)
│ └── meta charset="utf-8"
└── body
├── header
│ └── h1
│ └── "Bienvenidos" (texto)
└── main
└── p
├── "Este es un " (texto)
├── a href="#"
│ └── "enlace" (texto)
└── " de ejemplo." (texto)
Esta estructura permite relaciones familiares entre nodos:
- Nodo padre: El nodo que contiene directamente a otro nodo
- Nodo hijo: Cualquier nodo contenido directamente dentro de otro
- Nodos hermanos: Nodos que comparten el mismo padre
- Descendientes: Todos los nodos contenidos dentro de un nodo (hijos, nietos, etc.)
- Ancestros: Todos los nodos que contienen a un nodo (padre, abuelo, etc.)
Tipos de nodos en el DOM
El DOM define diferentes tipos de nodos, cada uno representado por una clase distinta en el sistema de objetos del DOM. Los más comunes son:
- Nodos de elemento (Element Node): Representan las etiquetas HTML como
<div>
,<p>
,<span>
. Son instancias de la claseElement
y sus subclases. - Nodos de texto (Text Node): Contienen el texto dentro de los elementos. Por ejemplo, en
<p>Hola mundo</p>
, "Hola mundo" es un nodo de texto hijo del elemento<p>
. - Nodos de atributo (Attribute Node): Representan los atributos de los elementos HTML como
class
,id
osrc
. - Nodos de comentario (Comment Node): Contienen los comentarios HTML (
<!-- comentario -->
). - Nodo documento (Document Node): El nodo raíz que representa el documento entero.
- Nodo de tipo documento (DocumentType Node): Representa la declaración del tipo de documento (
<!DOCTYPE html>
).
Podemos identificar estos tipos de nodos mediante la propiedad nodeType
, que devuelve un número representando el tipo de nodo:
// Explorando tipos de nodos
const element = document.querySelector('div'); // Nodo de elemento
const text = element.firstChild; // Posible nodo de texto
const comment = document.createComment('Nota'); // Nodo de comentario
console.log(element.nodeType); // 1 (ELEMENT_NODE)
console.log(text.nodeType); // 3 (TEXT_NODE) si el primer hijo es texto
console.log(document.nodeType); // 9 (DOCUMENT_NODE)
Esta organización en tipos de nodos es otro ejemplo de cómo el DOM utiliza conceptos de POO, con cada tipo de nodo siendo una clase especializada con propiedades y comportamientos específicos.
Navegación por el árbol DOM
El DOM proporciona propiedades de navegación que permiten moverse entre nodos relacionados:
// Propiedades de navegación básicas
const parent = element.parentNode; // Nodo padre
const firstChild = element.firstChild; // Primer hijo (puede ser texto)
const lastChild = element.lastChild; // Último hijo
const nextSibling = element.nextSibling; // Hermano siguiente
const previousSibling = element.previousSibling; // Hermano anterior
// Propiedades que solo navegan entre elementos (ignorando nodos de texto y comentarios)
const firstElementChild = element.firstElementChild; // Primer elemento hijo
const children = element.children; // Colección de elementos hijos
const nextElementSibling = element.nextElementSibling; // Siguiente elemento hermano
Veamos un ejemplo visual de cómo usar estas propiedades de navegación. Considerando este HTML:
<ul id="lista">
<li>Primero</li>
<li>Segundo</li>
<li>Tercero</li>
</ul>
Podemos navegar por su estructura DOM:
const lista = document.getElementById('lista');
const primerItem = lista.firstElementChild; // <li>Primero</li>
const segundoItem = primerItem.nextElementSibling; // <li>Segundo</li>
const tercerItem = lista.lastElementChild; // <li>Tercero</li>
Colecciones de nodos
El DOM utiliza colecciones especiales para representar grupos de nodos relacionados:
- NodeList: Colección de nodos devuelta por métodos como
querySelectorAll()
. Puede ser estática o dinámica. - HTMLCollection: Colección de elementos HTML devuelta por propiedades como
children
o métodos comogetElementsByClassName()
. Siempre es dinámica.
// NodeList estática (no se actualiza si el DOM cambia)
const parrafos = document.querySelectorAll('p');
// HTMLCollection dinámica (se actualiza automáticamente)
const elementosActivos = document.getElementsByClassName('active');
// Si añadimos un nuevo elemento con clase "active":
const nuevoElemento = document.createElement('div');
nuevoElemento.className = 'active';
document.body.appendChild(nuevoElemento);
console.log(elementosActivos.length); // Aumenta (refleja el cambio)
Es importante notar que aunque estas colecciones se parecen a arrays, son objetos especiales con propiedades y métodos limitados. Para trabajar con ellas como arrays completos, podemos convertirlas:
// Convertir NodeList a Array
const parrafosArray = Array.from(document.querySelectorAll('p'));
// o
const parrafosArray2 = [...document.querySelectorAll('p')];
Nodos especiales y su función
Algunos nodos tienen funciones específicas en la estructura del documento:
- El nodo
documentElement
(document.documentElement
) representa el elemento<html>
, la raíz del contenido. - Los nodos
head
(document.head
) ybody
(document.body
) proporcionan acceso directo a estas secciones. - Los nodos de fragmento (
DocumentFragment
) permiten construir estructuras DOM complejas fuera del árbol principal, mejorando el rendimiento.
El objeto document: Punto de entrada y métodos globales para interactuar con la página
El objeto document
representa el punto de entrada principal al árbol DOM y proporciona la interfaz fundamental para interactuar con el contenido de una página web. Este objeto es una instancia de la interfaz Document
y está disponible globalmente en cualquier script que se ejecute en un navegador.
Como vimos en nuestras lecciones sobre objetos en JavaScript, podemos pensar en document
como un objeto complejo con propiedades y métodos específicos:
// Algunas propiedades del objeto document
console.log(document.title); // El título de la página
console.log(document.URL); // La URL completa
console.log(document.doctype); // El tipo de documento (<!DOCTYPE>)
console.log(document.readyState); // Estado de carga del documento
Selección de elementos: Encontrando objetos en el árbol DOM
El objeto document
proporciona métodos para seleccionar elementos del DOM, esencialmente permitiéndonos buscar objetos específicos en el árbol:
// Métodos de selección modernos
const elemento = document.getElementById('miId'); // Elemento único con el ID especificado
const primerCoincidencia = document.querySelector('.miClase'); // Primer elemento que coincide con el selector
const todasCoincidencias = document.querySelectorAll('p'); // Todos los elementos que coinciden
// Ejemplos de selectores CSS avanzados
const elementosActivos = document.querySelectorAll('[data-estado="activo"]');
const itemsImpares = document.querySelectorAll('li:nth-child(odd)');
Estos métodos actúan como "buscadores" que recorren el árbol DOM para encontrar los elementos que necesitamos.
Creación y manipulación de elementos
Uno de los usos más poderosos del DOM es la capacidad de crear y manipular elementos dinámicamente. Aquí es donde realmente vemos cómo los elementos DOM son objetos JavaScript con propiedades y métodos:
// Crear un nuevo elemento (un objeto de tipo HTMLDivElement)
const nuevoDiv = document.createElement('div');
// Modificar sus propiedades
nuevoDiv.id = 'contenedor';
nuevoDiv.className = 'contenedor principal';
nuevoDiv.textContent = 'Este es un div creado dinámicamente';
// Añadir estilos (accediendo a su propiedad style, que también es un objeto)
nuevoDiv.style.color = 'blue';
nuevoDiv.style.backgroundColor = '#f0f0f0';
nuevoDiv.style.padding = '10px';
// Añadir al DOM
document.body.appendChild(nuevoDiv);
Observa cómo tratamos al elemento div
como un objeto, accediendo y modificando sus propiedades (id
, className
, textContent
, style
).
Ejemplo visual: Del HTML al DOM y la manipulación con JavaScript
Para entender la relación entre HTML, DOM y JavaScript, veamos un ejemplo completo:
HTML inicial:
<div id="app">
<h1>Mi Aplicación</h1>
<ul class="lista">
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
Estructura DOM resultante:
div#app
├── h1
│ └── "Mi Aplicación" (texto)
└── ul.lista
├── li
│ └── "Item 1" (texto)
└── li
└── "Item 2" (texto)
Código JavaScript para manipular esta estructura:
// Acceder a elementos existentes
const app = document.getElementById('app');
const titulo = app.querySelector('h1');
const lista = app.querySelector('.lista');
// Modificar contenido
titulo.textContent = 'Mi Aplicación Actualizada';
// Añadir nuevo elemento
const nuevoItem = document.createElement('li');
nuevoItem.textContent = 'Item 3';
lista.appendChild(nuevoItem);
// El DOM ahora representa:
// div#app
// ├── h1
// │ └── "Mi Aplicación Actualizada" (texto)
// └── ul.lista
// ├── li
// │ └── "Item 1" (texto)
// ├── li
// │ └── "Item 2" (texto)
// └── li
// └── "Item 3" (texto)
Gestión de eventos a nivel de documento
Los eventos son la forma en que el DOM permite que la página responda a las acciones del usuario. Siguiendo el paradigma de programación orientada a objetos, los eventos se implementan mediante el patrón Observer:
// Añadir un "escuchador" a un elemento
const boton = document.querySelector('button');
boton.addEventListener('click', function() {
console.log('¡El botón fue clicado!');
});
// También podemos añadir escuchadores a nivel de documento
document.addEventListener('keydown', function(evento) {
console.log('Tecla presionada:', evento.key);
});
Este patrón de evento-handler es similar a cómo implementamos comportamientos en objetos en la programación orientada a objetos.
Propiedades y métodos para trabajar con formularios
El objeto document
proporciona acceso directo a los formularios del documento:
// Acceso a formularios
const allForms = document.forms; // HTMLCollection de todos los formularios
const formById = document.forms.formId; // Acceso por ID
const formByIndex = document.forms[0]; // Acceso por índice
// Acceso a elementos de formulario
const inputElement = document.forms.loginForm.username;
Métodos para trabajar con la estructura del documento
El objeto document
proporciona métodos para importar y adoptar nodos entre documentos:
// Importar un nodo desde otro documento
const importedNode = document.importNode(externalNode, true); // true para importar descendientes
// Adoptar un nodo de otro documento
const adoptedNode = document.adoptNode(externalNode);
Propiedades relacionadas con el estado de carga
El objeto document
proporciona información sobre el estado de carga de la página:
// Comprobar si el DOM está listo
if (document.readyState === 'loading') {
console.log('El documento está cargando');
} else {
console.log('El documento ha terminado de cargar');
}
// Escuchar cambios en el estado de carga
document.addEventListener('readystatechange', () => {
console.log('Estado del documento:', document.readyState);
});
Métodos para trabajar con la selección de texto
El objeto document
permite gestionar la selección de texto en la página:
// Obtener la selección actual
const selection = document.getSelection();
console.log('Texto seleccionado:', selection.toString());
// Crear un rango
const range = document.createRange();
const paragraph = document.querySelector('p');
range.selectNodeContents(paragraph); // Selecciona todo el contenido del párrafo
// Aplicar un rango a la selección
selection.removeAllRanges();
selection.addRange(range);
El objeto document
es el núcleo de la interacción con el DOM, proporcionando los métodos y propiedades fundamentales que permiten a JavaScript manipular dinámicamente el contenido, estructura y comportamiento de una página web.
Otras lecciones de JavaScript
Accede a todas las lecciones de JavaScript y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Javascript
Introducción Y Entorno
Tipos De Datos
Sintaxis
Variables
Sintaxis
Operadores
Sintaxis
Estructuras De Control
Sintaxis
Funciones
Sintaxis
Funciones Cierre (Closure)
Sintaxis
Métodos De Strings
Sintaxis
Funciones Cierre (Closure)
Sintaxis
Operadores Avanzados
Sintaxis
Funciones
Sintaxis
Expresiones Regulares
Sintaxis
Estructuras De Control
Sintaxis
Arrays Y Métodos
Estructuras De Datos
Conjuntos Con Set
Estructuras De Datos
Mapas Con Map
Estructuras De Datos
Conjuntos Con Set
Estructuras De Datos
Funciones Flecha
Programación Funcional
Filtrado Con Filter() Y Find()
Programación Funcional
Transformación Con Map()
Programación Funcional
Reducción Con Reduce()
Programación Funcional
Funciones Flecha
Programación Funcional
Transformación Con Map()
Programación Funcional
Inmutabilidad Y Programación Funcional Pura
Programación Funcional
Clases Y Objetos
Programación Orientada A Objetos
Excepciones
Programación Orientada A Objetos
Encapsulación
Programación Orientada A Objetos
Herencia
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
This Y Contexto
Programación Orientada A Objetos
Patrón De Módulos Y Namespace
Programación Orientada A Objetos
Prototipos Y Cadena De Prototipos
Programación Orientada A Objetos
Destructuring De Objetos Y Arrays
Programación Orientada A Objetos
Manipulación Dom
Dom
Selección De Elementos Dom
Dom
Modificación De Elementos Dom
Dom
Eventos Del Dom
Dom
Localstorage Y Sessionstorage
Dom
Bom (Browser Object Model)
Dom
Callbacks
Programación Asíncrona
Promises
Programación Asíncrona
Async / Await
Programación Asíncrona
Api Fetch
Programación Asíncrona
Naturaleza De Js Y Event Loop
Programación Asíncrona
Websockets
Programación Asíncrona
Módulos En Es6
Construcción
Configuración De Bundlers Como Vite
Construcción
Eslint Y Calidad De Código
Construcción
Npm Y Dependencias
Construcción
Introducción A Pruebas En Js
Testing
Pruebas Unitarias
Testing
Ejercicios de programación de JavaScript
Evalúa tus conocimientos de esta lección Introducción al DOM con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Excepciones
Transformación con map()
Arrays y Métodos
Reto Métodos de Strings
Transformación con map()
Funciones flecha
Selección de elementos DOM
API Fetch
Encapsulación
Mapas con Map
Creación y uso de variables
Polimorfismo
Reto Funciones flecha
Tipos de datos
Reto Operadores avanzados
Reto Estructuras de control
Estructuras de control
Pruebas unitarias
Inmutabilidad y programación funcional pura
Funciones flecha
Polimorfismo
Reto Polimorfismo
Array
Transformación con map()
Reto Variables
Gestor de tareas con JavaScript
Proyecto Modificación de elementos DOM
Manipulación DOM
Funciones
Conjuntos con Set
Reto Prototipos y cadena de prototipos
Reto Encapsulación
Funciones flecha
Async / Await
Reto Excepciones
Reto Filtrado con filter() y find()
Reto Promises
Creación y uso de variables
Excepciones
Promises
Funciones cierre (closure)
Reto Herencia
Herencia
Reto Async / Await
Proyecto Eventos del DOM
Herencia
Selección de elementos DOM
Modificación de elementos DOM
Reto Clases y objetos
Filtrado con filter() y find()
Funciones cierre (closure)
Reto Destructuring de objetos y arrays
Callbacks
Funciones
Mapas con Map
Reducción con reduce()
Callbacks
Manipulación DOM
Introducción al DOM
Reto Funciones
Reto Funciones cierre (closure)
Promises
Reto Reducción con reduce()
Async / Await
Reto Estructuras de control
Eventos del DOM
Introducción a JavaScript
Async / Await
Promises
Selección de elementos DOM
Filtrado con filter() y find()
Callbacks
Creación de clases y objetos Restaurante
Reducción con reduce()
Filtrado con filter() y find()
Reducción con reduce()
Conjuntos con Set
Herencia de clases
Eventos del DOM
Clases y objetos
Modificación de elementos DOM
Mapas con Map
Proyecto carrito compra agoodshop
Introducción a JavaScript
Reto Mapas con Map
Funciones
Proyecto administrador de contactos
Reto Expresiones regulares
Tipos de datos
Clases y objetos
Array
Conjuntos con Set
Array
Encapsulación
Clases y objetos
Uso de operadores
Uso de operadores
Estructuras de control
Proyecto Manipulación DOM
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender la estructura y funciones del Document Object Model (DOM).
- Aprender a acceder y modificar elementos HTML usando JavaScript.
- Conocer la jerarquía y tipos de nodos en el DOM.
- Optimizar las manipulaciones del DOM para mejorar el rendimiento.
- Identificar los estándares y versiones del DOM soportados por navegadores.