Let’s get a more in-depth look at DOM nodes.
In this chapter we’ll see more into what they are and learn their most used properties.
DOM node classes
Different DOM nodes may have different properties. For instance, an element node corresponding to tag <a> has link-related properties, and the one corresponding to <input> has input-related properties and so on. Text nodes are not the same as element nodes. But there are also common properties and methods between all of them, because all classes of DOM nodes form a single hierarchy.
Each DOM node belongs to the corresponding built-in class.
The root of the hierarchy is EventTarget, that is inherited by Node, and other DOM nodes inherit from it.
Here’s the picture, explanations to follow:
The classes are:
-
EventTarget – is the root “abstract” class for everything.
Objects of that class are never created. It serves as a base, so that all DOM nodes support so-called “events”, we’ll study them later.
-
Node – is also an “abstract” class, serving as a base for DOM nodes.
It provides the core tree functionality:
parentNode,nextSibling,childNodesand so on (they are getters). Objects ofNodeclass are never created. But there are other classes that inherit from it (and so inherit theNodefunctionality). -
Document, for historical reasons often inherited by
HTMLDocument(though the latest spec doesn’t dictate it) – is a document as a whole.The
documentglobal object belongs exactly to this class. It serves as an entry point to the DOM. -
CharacterData – an “abstract” class, inherited by:
-
Element – is the base class for DOM elements.
It provides element-level navigation like
nextElementSibling,childrenand searching methods likegetElementsByTagName,querySelector.A browser supports not only HTML, but also XML and SVG. So the
Elementclass serves as a base for more specific classes:SVGElement,XMLElement(we don’t need them here) andHTMLElement. -
Finally, HTMLElement is the basic class for all HTML elements. We’ll work with it most of the time.
It is inherited by concrete HTML elements:
- HTMLInputElement – the class for
<input>elements, - HTMLBodyElement – the class for
<body>elements, - HTMLAnchorElement – the class for
<a>elements, - …and so on.
- HTMLInputElement – the class for
There are many other tags with their own classes that may have specific properties and methods, while some elements, such as <span>, <section>, <article> do not have any specific properties, so they are instances of HTMLElement class.
So, the full set of properties and methods of a given node comes as the result of the chain of inheritance.
For example, let’s consider the DOM object for an <input> element. It belongs to HTMLInputElement class.
It gets properties and methods as a superposition of (listed in inheritance order):
HTMLInputElement– this class provides input-specific properties,HTMLElement– it provides common HTML element methods (and getters/setters),Element– provides generic element methods,Node– provides common DOM node properties,EventTarget– gives the support for events (to be covered),- …and finally it inherits from
Object, so “plain object” methods likehasOwnPropertyare also available.
To see the DOM node class name, we can recall that an object usually has the constructor property. It references the class constructor, and constructor.name is its name:
alert( document.body.constructor.name ); // HTMLBodyElement
…Or we can just toString it:
alert( document.body ); // [object HTMLBodyElement]
We also can use instanceof to check the inheritance:
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
As we can see, DOM nodes are regular JavaScript objects. They use prototype-based classes for inheritance.
That’s also easy to see by outputting an element with console.dir(elem) in a browser. There in the console you can see HTMLElement.prototype, Element.prototype and so on.
console.dir(elem) versus console.log(elem)Most browsers support two commands in their developer tools: console.log and console.dir. They output their arguments to the console. For JavaScript objects these commands usually do the same.
But for DOM elements they are different:
console.log(elem)shows the element DOM tree.console.dir(elem)shows the element as a DOM object, good to explore its properties.
Try it on document.body.
In the specification, DOM classes aren’t described by using JavaScript, but a special Interface description language (IDL), that is usually easy to understand.
In IDL all properties are prepended with their types. For instance, DOMString, boolean and so on.
Here’s an excerpt from it, with comments:
// Define HTMLInputElement
// The colon ":" means that HTMLInputElement inherits from HTMLElement
interface HTMLInputElement: HTMLElement {
// here go properties and methods of <input> elements
// "DOMString" means that the value of a property is a string
attribute DOMString accept;
attribute DOMString alt;
attribute DOMString autocomplete;
attribute DOMString value;
// boolean value property (true/false)
attribute boolean autofocus;
...
// now the method: "void" means that the method returns no value
void select();
...
}
The “nodeType” property
The nodeType property provides one more, “old-fashioned” way to get the “type” of a DOM node.
It has a numeric value:
elem.nodeType == 1for element nodes,elem.nodeType == 3for text nodes,elem.nodeType == 9for the document object,- there are few other values in the specification.
For instance:
<body>
<script>
let elem = document.body;
// let's examine: what type of node is in elem?
alert(elem.nodeType); // 1 => element
// and its first child is...
alert(elem.firstChild.nodeType); // 3 => text
// for the document object, the type is 9
alert( document.nodeType ); // 9
</script>
</body>
In modern scripts, we can use instanceof and other class-based tests to see the node type, but sometimes nodeType may be simpler. We can only read nodeType, not change it.
Tag: nodeName and tagName
Given a DOM node, we can read its tag name from nodeName or tagName properties:
For instance:
alert( document.body.nodeName ); // BODY
alert( document.body.tagName ); // BODY
Is there any difference between tagName and nodeName?
Sure, the difference is reflected in their names, but is indeed a bit subtle.
- The
tagNameproperty exists only forElementnodes. - The
nodeNameis defined for anyNode:- for elements it means the same as
tagName. - for other node types (text, comment, etc.) it has a string with the node type.
- for elements it means the same as
In other words, tagName is only supported by element nodes (as it originates from Element class), while nodeName can say something about other node types.
For instance, let’s compare tagName and nodeName for the document and a comment node:
<body><!-- comment -->
<script>
// for comment
alert( document.body.firstChild.tagName ); // undefined (not an element)
alert( document.body.firstChild.nodeName ); // #comment
// for document
alert( document.tagName ); // undefined (not an element)
alert( document.nodeName ); // #document
</script>
</body>
If we only deal with elements, then we can use both tagName and nodeName – there’s no difference.
The browser has two modes of processing documents: HTML and XML. Usually the HTML-mode is used for webpages. XML-mode is enabled when the browser receives an XML-document with the header: Content-Type: application/xml+xhtml.
In HTML mode tagName/nodeName is always uppercased: it’s BODY either for <body> or <BoDy>.
In XML mode the case is kept “as is”. Nowadays XML mode is rarely used.
innerHTML: the contents
The innerHTML property allows to get the HTML inside the element as a string.
We can also modify it. So it’s one of the most powerful ways to change the page.
The example shows the contents of document.body and then replaces it completely:
<body>
<p>A paragraph</p>
<div>A div</div>
<script>
alert( document.body.innerHTML ); // read the current contents
document.body.innerHTML = 'The new BODY!'; // replace it
</script>
</body>
We can try to insert invalid HTML, the browser will fix our errors:
<body>
<script>
document.body.innerHTML = '<b>test'; // forgot to close the tag
alert( document.body.innerHTML ); // <b>test</b> (fixed)
</script>
</body>
If innerHTML inserts a <script> tag into the document – it becomes a part of HTML, but doesn’t execute.
Beware: “innerHTML+=” does a full overwrite
We can append HTML to an element by using elem.innerHTML+="more html".
Like this: