Echemos un mirada más en profundidad a los nodos DOM.
En este capítulo veremos más sobre cuáles son y aprenderemos sus propiedades más utilizadas.
Clases de nodo DOM
Los diferentes nodos DOM pueden tener diferentes propiedades. Por ejemplo, un nodo de elemento correspondiente a la etiqueta <a> tiene propiedades relacionadas con el enlace, y el correspondiente a <input> tiene propiedades relacionadas con la entrada y así sucesivamente. Los nodos de texto no son lo mismo que los nodos de elementos. Pero también hay propiedades y métodos comunes entre todos ellos, porque todas las clases de nodos DOM forman una única jerarquía.
Cada nodo DOM pertenece a la clase nativa correspondiente.
La raíz de la jerarquía es EventTarget, que es heredada por Node, y otros nodos DOM heredan de él.
Aquí está la imagen, con las explicaciones a continuación:
Las clases son:
-
EventTarget – es la clase raíz “abstracta”.
Los objetos de esta clase nunca se crean. Sirve como base, es por la que todos los nodos DOM soportan los llamados “eventos” que estudiaremos más adelante.
-
Node – también es una clase “abstracta”, sirve como base para los nodos DOM.
Proporciona la funcionalidad del árbol principal:
parentNode,nextSibling,childNodesy demás (son getters). Los objetos de la claseNodenunca se crean. Pero hay clases de nodos concretas que heredan de ella (y también heredan la funcionalidad deNode). -
Document, por razones históricas, heredado a menudo por
HTMLDocument(aunque la última especificación no lo exige) – es el documento como un todo.El objeto global
documentpertenece exactamente a esta clase. Sirve como punto de entrada al DOM. -
CharacterData – una clase “abstract” heredada por:
-
Element – es una clase base para elementos DOM.
Proporciona navegación a nivel de elemento como
nextElementSibling,childreny métodos de búsqueda comogetElementsByTagName,querySelector.Un navegador admite no solo HTML, sino también XML y SVG. La clase
Elementsirve como base para clases más específicas:SVGElement,XMLElement(no las necesitamos aquí) yHTMLElement. -
Finalmente, HTMLElement – es la clase básica para todos los elementos HTML. Trabajaremos con ella la mayor parte del tiempo.
Es heredado por elementos HTML concretos:
- HTMLInputElement – la clase para elementos
<input>, - HTMLBodyElement – la clase para los elementos
<body>, - HTMLAnchorElement – la clase para elementos
<a>, - …y así sucesivamente.
- HTMLInputElement – la clase para elementos
Hay muchas otras etiquetas con sus propias clases que pueden tener propiedades y métodos específicos, mientras que algunos elementos, tales como <span>, <section>, <article>, no tienen ninguna propiedad específica entonces derivan de la clase HTMLElement.
Entonces, el conjunto completo de propiedades y métodos de un nodo dado viene como resultado de la cadena de herencia.
Por ejemplo, consideremos el objeto DOM para un elemento <input>. Pertenece a la clase HTMLInputElement.
Obtiene propiedades y métodos como una superposición de (enumerados en orden de herencia):
HTMLInputElement– esta clase proporciona propiedades específicas de entrada,HTMLElement– proporciona métodos de elementos HTML comunes (y getters/setters),Element– proporciona métodos de elementos genéricos,Node– proporciona propiedades comunes del nodo DOM,EventTarget– da el apoyo para eventos (a cubrir),- …y finalmente hereda de
Object, por lo que también están disponibles métodos de “objeto simple” comohasOwnProperty.
Para ver el nombre de la clase del nodo DOM, podemos recordar que un objeto generalmente tiene la propiedad constructor. Hace referencia al constructor de la clase, y constructor.name es su nombre:
alert( document.body.constructor.name ); // HTMLBodyElement
…O podemos simplemente usar toString:
alert( document.body ); // [object HTMLBodyElement]
También podemos usar instanceof para verificar la herencia:
alert( document.body instanceof HTMLBodyElement ); // true
alert( document.body instanceof HTMLElement ); // true
alert( document.body instanceof Element ); // true
alert( document.body instanceof Node ); // true
alert( document.body instanceof EventTarget ); // true
Como podemos ver, los nodos DOM son objetos regulares de JavaScript. Usan clases basadas en prototipos para la herencia.
Eso también es fácil de ver al generar un elemento con console.dir(elem) en un navegador. Allí, en la consola, puede ver HTMLElement.prototype, Element.prototype y así sucesivamente.
console.dir(elem) versus console.log(elem)La mayoría de los navegadores admiten dos comandos en sus herramientas de desarrollo: console.log y console.dir. Envían sus argumentos a la consola. Para los objetos JavaScript, estos comandos suelen hacer lo mismo.
Pero para los elementos DOM son diferentes:
console.log(elem)muestra el árbol DOM del elemento.console.dir(elem)muestra el elemento como un objeto DOM, es bueno para explorar sus propiedades.
Inténtalo en document.body.
En la especificación, las clases DOM no se describen mediante JavaScript, sino con un Lenguaje de descripción de interfaz (IDL) especial, que suele ser fácil de entender.
En IDL, todas las propiedades están precedidas por sus tipos. Por ejemplo, DOMString, boolean y así sucesivamente.
Aquí hay un extracto, con comentarios:
// Definir HTMLInputElement
// Los dos puntos ":" significan que HTMLInputElement hereda de HTMLElement
interface HTMLInputElement: HTMLElement {
// aquí van las propiedades y métodos de los elementos <input>
// "DOMString" significa que el valor de una propiedad es un string
attribute DOMString accept;
attribute DOMString alt;
attribute DOMString autocomplete;
attribute DOMString value;
// Propiedad de valor booleano (true/false)
attribute boolean autofocus;
...
// ahora el método: "void" significa que el método no devuelve ningún valor
void select();
...
}
La propiedad “nodeType”
La propiedad nodeType proporciona una forma “anticuada” más de obtener el “tipo” de un nodo DOM.
Tiene un valor numérico:
elem.nodeType == 1para nodos de elementos,elem.nodeType == 3para nodos de texto,elem.nodeType == 9para el objeto de documento,- hay algunos otros valores en la especificación.
Por ejemplo:
<body>
<script>
let elem = document.body;
// vamos a examinar: ¿qué tipo de nodo es elem?
alert(elem.nodeType); // 1 => elemento
// Y el primer hijo es...
alert(elem.firstChild.nodeType); // 3 => texto
// para el objeto de tipo documento, el tipo es 9
alert( document.nodeType ); // 9
</script>
</body>
En los scripts modernos, podemos usar instanceof y otras pruebas basadas en clases para ver el tipo de nodo, pero a veces nodeType puede ser más simple. Solo podemos leer nodeType, no cambiarlo.
Tag: nodeName y tagName
Dado un nodo DOM, podemos leer su nombre de etiqueta en las propiedades de nodeName o tagName:
Por ejemplo:
alert( document.body.nodeName ); // BODY
alert( document.body.tagName ); // BODY
¿Hay alguna diferencia entre tagName y nodeName?
Claro, la diferencia se refleja en sus nombres, pero de hecho es un poco sutil.
- La propiedad
tagNameexiste solo para los nodosElement. - El
nodeNamese define para cualquierNode:- para los elementos, significa lo mismo que
tagName. - para otros tipos de nodo (texto, comentario, etc.) tiene una cadena con el tipo de nodo.
- para los elementos, significa lo mismo que
En otras palabras, tagName solo es compatible con los nodos de elementos (ya que se origina en la clase Element), mientras que nodeName puede decir algo sobre otros tipos de nodos.
Por ejemplo, comparemos tagName y nodeName para document y un nodo de comentario:
<body><!-- comentario -->
<script>
// para comentarios
alert( document.body.firstChild.tagName ); // undefined (no es un elemento)
alert( document.body.firstChild.nodeName ); // #comment
// para documentos
alert( document.tagName ); // undefined (no es un elemento)
alert( document.nodeName ); // #document
</script>
</body>