Objective
Redefine the firstElementChild
property of the Element
interface, manually in JavaScript.
Difficulty
Description
In the previous HTML DOM — Elements chapter, we learnt about the firstElementChild
property of the Element
interface.
It returns the first child node of the calling element that is an element itself, or else the value null
if there is no element child node in the calling element or just about no child node at all.
In this exercise, you have to redefine firstElementChild
on the Element
interface, manually in JavaScript.
You MUST only use properties/methods of the Node
interface in your code, NOT any properties/methods of the Element
interface, such as children
.
New file
Inside the directory you created for this course on JavaScript, create a new folder called Exercise-41-Redefining-firstElementChild and put the .html solution files for this exercise within it.
Solution
What we need is simply a while
loop that keeps iterating over each subsequent child node of the calling element until an Element
instance is found.
Technically, we can use childNodes
to accomplish this task, but we're better off at using the firstChild
and the nextSibling
properties together and thus make the implementation shorter and simpler.
The code below implements the firstElementChild
property:
Object.defineProperty(Element.prototype, 'firstElementChild', {
get: function() {
var element = this.firstChild;
while (element && !(element instanceof Element)) {
element = element.nextSibling;
}
return element;
}
});
Time to try out the implementation.
Consider the following HTML code:
<div id="main">
<h1>A heading</h1>
<p>A paragraph</p>
</div>
In the snippet below, we retrieve the nodeName
of the first element child of the #main
element:
var mainElement = document.getElementById('main').firstElementChild.nodeName
'H1'
Since the nodeName
is 'H1'
, this means that firstElementChild
selected the <h1>
element, and not the first child text node of <#main>
.
But how can we be sure that it's our implementation that's being called? Well, simply by adding a console log statement in there.
In the code below, we add a simple console.log()
statement in the definition of firstElementChild
:
Object.defineProperty(Element.prototype, 'firstElementChild', {
get: function() {
console.log('firstElementChild executing');
var element = this.firstChild;
while (element && !(element instanceof Element)) {
element = element.nextSibling;
}
return element;
}
});
Now let's reperform the nodeName
check on firstElementChild
:
var mainElement = document.getElementById('main').firstElementChild.nodeName
'H1'