DOM text nodes: methods disguised as properties?


#1

I’m learning about the DOM. I’m finding the design really strange because

telem.innerHTML = "<em>Hello</em> World!";

is assigned as a property rather than invoked as a method. From my understanding, that string is heavily parsed before it gets appended to the DOM via the innerHTML property. Meaning, <em>Hello</em> is a new element node with an accompanying child text node, “Hello” as well as “World!” becoming a sibling to <em>.

elem.textContent on the other hand behaves the way I’d expect a property to behave. On the surface at least, modifying the textContent property is just a simple string assignment.

With so much going on under the hood, why wouldn’t innerHTML be invoked as a method? Is this kind of interface design consistent throughout the DOM?


#2

Hi @austen really interessting question. I found this thread on Stackoverflow as a good starting point:

The DOM-Implementation of JS is a mess because a lot of different interest-groups (Companies) had their hand in it. As you say in German: " Too many cooks spoil the broth".

A lot of work has been done in the last years to clean it up, but the old things will remain, because you want to be able to browse old sites with a modern browser. So every new browser has to support the new things and ALL the old stuff.


#3

That’s too bad. Hopefully back-end JS development is more thoughtfully implemented. I guess I’ll find out when I get there.


#4

I think I understand what’s going on with this “method disguised as property” phenomenon! I’ve been reading about JS setters and getters. Basically, innerHTML must have some kind of invisible (to the user) set method that parses in when innerHTML is assigned a string. I don’t know why anyone would want that. Why not just use a method interface in that case? Is there a case where the method interface is too cumbersome or completely unworkable? I don’t get it, but there you go. I now have an explanation that lets me sleep at night. :slight_smile:


#5

I’ve found a good application for setter-getter methods that involves prototypes! I came up with this while working of LJSTHW ex24 OOP game.
If you have a multiplayer game where every teamPlayer (extends Player) shares the same score, you can refer back to the player prototype (assuming all players are inheriting from a prototype) which contains the score property. Use a setter/getter to have all the teamPlayers change the shared score. For soloPlayers, you can extend the Player class, but shadow the shared score of the Player class. I haven’t come up with an example for soloPlayer, but here’s something like teamPlayer.

#!/usr/bin/env node
class Player {
    constructor (value) {
        this.score = value
    }   
}

class teamPlayer extends Player {
    // using set/get methods to make score property refer back to prototype
    // so that all teamPlayers share the same score
    set score(value) {
        this.__proto__.score = value;
    }   
    get score() {
        return this.__proto__.score;
    }   
}

// even when each teamPlayer is instantiated with a unique argument, the value
// is assigned to the __proto__ score
let Baba = new teamPlayer(0); // 
let Jojo = new teamPlayer(10); // 

console.log("Baba score: ", Baba.score); // Baba score: 10
console.log("Jojo score: ", Jojo.score); // Jojo score: 10

// it also applies to assignment after instantiation
Baba.score = 5;
Jojo.score += 2;

console.log("Baba score: ", Baba.score); // Baba score: 7
console.log("Jojo score: ", Jojo.score); // Jojo score: 7

Why should I use set/get on teamPlayer instead of a method? Here’s why! It’s because there may be other Player methods inherited by both teamPlayer and soloPlayer subclasses which need to read or write the player’s score.

For example, Player.double-score() might be a method which reads the player’s score and doubles it. If we used the teamPlayer explicit set/get score methods to modify the prototype’s (Player’s) score, then we’d also have to write explicit set/get methods for the soloPlayer class. If you start requiring explicit set/get methods for all properties of all subclasses, that could end up being a lot more code to maintain. Using properties that are assigned/accessed via “invisible” (“implicit”?) setters/getters can make for much cleaner, easily maintained code.

Does this make sense?