I have a weird JavaScript behavior which I cannot explain.
Consider this code:
var el = document.createElement('div')
var s = String.fromCharCode(160)
el.innerHTML = s
console.log(s) // prints space
console.log(el.innerHTML) // prints " "
Now I know that  
is non-breaking space, but technically, I just made an assignment of one variable to another, both are strings.
How come the values are different?
Is innerHTML
a special kind of string or something?
How does it work? What Is the mechanism which translates this?
innerHTML
is not a simple property, it's an accessor property with getter
and setter
. Means that under the hood functions work. innerHTML
serializes the given input into HTML. It parses the given value, creates elements and nodes, then appends those ones to the element.
It is defined like this
const DOMElement = {
value: null,
set innerHTML(html) {
console.log(`Setting html: ${html}`);
// Translate into elements and nodes, then append to the element
this.value = html;
},
get innerHTML() {
console.log(`Getting html:`);
// Translate into string, then return it
return this.value;
}
};
DOMElement.innerHTML = '<p>Hello</p>';
console.log(DOMElement.innerHTML);
If you want to print the given character without serializing, you can use textContent
property.
technically, I just made an assignment of one variable to another, both are strings. How come the values are different?
Because yes, innerHTML
is special. It's not just a simple value property, it's an accessor property. When you assign to it, you're calling a function under-the-covers which parses the HTML you give it and creates the necessary DOM nodes and elements. When you read its value, you're calling another function under-the-covers which recurses through the DOM tree starting from the element on which you access it and builds an HTML string representing that DOM tree.
So while you assigned the character U+00A0 to it, that got turned into a DOM text node; and when you read from it, that DOM text node was rendered as a canonical (per that browser's rules) HTML string:
.
You can see that innerHTML
isn't just a simple value property by using the DOM to manipulate the element:
var target = document.getElementById("target");
target.innerHTML = "\u00A0";
console.log(target.innerHTML); // " "
target.appendChild(
document.createElement("span")
);
console.log(target.innerHTML); // " <span></span>"
<div id="target"></div>
Note that it's possible to define accessor properties in JavaScript objects as well; it's not just the DOM that can have them:
var o = {
get foo() {
console.log("foo getter called");
return this._foo;
},
set foo(value) {
console.log("foo setter called");
this._foo = value;
}
};
console.log("foo: " + o.foo);
o.foo = 42;
console.log("foo: " + o.foo);
The fact that innerHTML
is a property with a getter and setter is why code like this is poor practice:
for (var n = 0; n < something.length; ++n) {
element.innerHTML += ", " + something[n];
}
That's constantly building and then destroying and rebuilding a DOM tree and making a bunch of hidden function calls. Instead, you'd build the string, then assign it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With