Blog

Front End Development topics with a touch of humor

This part trois

This never ends

October 3, 2020


In an earlier post, I said I'd concentrate on topics and situations that I've experienced in regards to this (as opposed to rare and academic ones). That means that this in classes should be front and center.

I don't know about you, but my progression in learning about classes was like:

Ours is not to question why...

This will make a lot more sense if you've delved into React. React, in case you are not one of the initiated, is a popular front end library--that acts very similarly to a framework but it isn't definitely isn't a framework--and it uses classes as a prominent feature.

Except now they're getting rid of classes...

But let's not worry about that. We're just leaves in the wind of change, and it is not ours to wonder why, merely to do, and--read a lot of docs.

This in classes

Classes are templates for objects. Let's create a class that will deal with Characters in a role-playing game. Observe the syntax:

            class Character {
                constructor(name, profession, level) {
                    this.name = name;
                    this.profession = profession;
                    this.level = level;
                }
                fight() {
                    console.log("fights");
                }
                flees() {
                    console.log("flees");
                }
            }
        

Quickly we see how classes are related to the top. Our old friend this pops up, not even being subtle about it! But what's going on here?

Consider that a class is a template--like a blueprint, if you will. A blueprint doesn't do anything--it's more like an idea, or a Platonic ideal. It just sits there on the drafting table and looks all unfinished. Nothing happens with a class until an instance is made.

            const grogg = new Character("Grogg", "barbarian", 6);
            
            console.log(grogg);
            //Character
        

Character is the class. By using the new keyword, I made an instance of Character (a new object) and passed several arguments to it. Those arguments go into the constructor and then, via the magic of this, become assigned to the new object.

            console.log(grogg.name);
            //"Grogg"

            console.log(grogg.profession);
            //"barbarian"
        

This, then, in a constructor function, refers to the newly created object. In this case, grogg is the new object. We used thisto assign the arguments that were supplied to the corresponding properties of the new object.

By the way, just to clear up a question that I had when I was learning this, the constructor function properties do not have to have the same names as the arguments. They usually do, but that's just by convention.

            class BizarroCharacter {
                constructor(name, profession, level) {
                    this.name = profession;
                    this.profession = name;
                    this.weirdnessFactor = level;
                }
                fight() {
                    console.log("fights");
                }
                flees() {
                    console.log("flees");
                }
            }
            const ggorg = new BizarroCharacter("Grogg", "barbarian", 5);
            console.log(ggorg.name);
            //"barbarian"
            console.log(ggorg.profession);
            //"name"
            console.log(weirdnessFactor):
            //5
        

In this new class, BizarroCharacter, the name is assigned to profession, and profession is signed to name. Level is assigned to weirdnessFactor. So it doesn't have to be this.name = name; that's just a convention. Now that we know this, you probably should follow this convention unless you have a very good reason to do so. This stuff is complicated enough without making it hard to follow!

Derived classes

Say you want to make a new class based on Character that keeps all the old cool qualites of Character and builds on it. This new class, however, called "NPC," will have need a new property, "location," which is the place the NPC can always be found lurking or hanging around.

            class NPC extends Character {
                constructor(location) {
                    location = this.location;
                }
            }

            const innkeeper = new NPC("The Green Griffon");
            console.log(innkeeper.location);
            //Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor at new NPC.
        

Oops, error! What happened here?

Remember I said I'd stick to real-life examples? Well, this is one! NPC, being a derived class of Character, is subject to a special rule, yet another one we must remember, in that it has no initial this binding.

So all that stuff about this.name = name and stuff for classes? Yeah, all goes out the window. Derived classes have no this.

But don't worry. As you can see, JavaScript very helpfully tells us exactly what's wrong and how to fix it. We can solve it in a single change.

            class NPC extends Character {
                constructor(location) {
                    super();
                    this.location = location;
                }
            }

            const innkeeper = new NPC("The Green Griffon");
            console.log(innkeeper.location);
            //"The Green Griffon"
        

Yay, it works now! Super(), as MDN says: must be called before you can use 'this'. Leaving this out will cause a reference error

More on that later. Enjoy your classes!