From Object Oriented JavaScript (Part the First)

var literalDog = {        // declaration AND instantiation
    name: "Vincent",      // object property
    speak: function() {   // object method
        return this.name + " says woof";
    }
};

literalDog.speak();  // "Vincent says woof"

Inside of the speak method the this variable will refer to the current context of the function execution. This is an important distinction with classically object oriented languages: the value of this can (and often does) change! In most cases, this inside of a method like the one above will refer to the current object or instance. Without some other influence, if a method is called with “dot” syntax as in the last line above, then you can generally expect this inside the function to be whatever is on the left side of the dot. Inside of literalDog.speak() the this variable will refer to the object left of the dot: literalDog.

function Dog(name) {
    if (name) { this.name = name; }
    this.speak = function() {
        return this.name + " says woof";
    }
}

var v = new Dog("Vincent");

First of all, the use of the capitol “D” in Dog is only done by convention, this is not a requirement of the language.

which obviously leads to

any function in JavaScript can be used as a “constructor” …

So, naturally

If Dog is just a regular function, why don’t we just call it normally? Why do we need to use the new keyword?

Yeah man, why?

To answer that, we have to understand that every function in JavaScript has a concept of a prototype; which is, generally speaking, a representation of what the newly created instance should be.

So, a function is an object. An object that uses this prototype concept to define itself. As a result, when we are calling the new reserved keyword, what happens is three of the following things.

Create an empty object;

set the new object’s prototype to point to the prototype;

and call the constructor method on the new object.

The reason for illustrating what the new keyword is doing is to highlight that it is not the same as classically inherited languages. In JavaScript, new is syntactic sugar and nothing else.

I am not sure why but I really liked this explanation. JavaScript has a lot of interesting concepts that you don’t really need to master in order for everything to work.

I went ahead with his example

function Dog(name){
if (name) { this.name = name; }
this.speak = function() {
return this.name + " says woof";
}
}

and then I used it the regular way that I am used to

var doggo = new Dog("Thunder");
doggo.speak();
> "Thunder says woof"

but I also implemented it the new way. I am not used to creating objects this way, but it adds to my javascript knowledge for sure

var otherDoggo = Object.create(Dog.prototype); // step 1 and step 2
otherDoggo.constructor("Thunder"); // step 3
otherDoggo.speak();
> "Thunder says woof"

To be honest with you, I would prefer to use it this way just because it allows me to context switch between other concepts and javascript way faster. Seeing the new keyword almost automatically makes me think in a wrong way.

To which the author of the article made a note

There are some people in the JavaScript community who feel that syntactic sugar like the new keyword does more harm than good and choose not to use it at all. However, with ECMAScript 6 (ES6) pushing for more syntactic sugar surrounding OOP, it is unlikely that it will lose favor on a wider scale.

and that is so. People prefer to write shorter syntax but I believe it makes learning such a weird language a bit more challenging. Which is fine.

A side issue — which is prevelant everywhere in software — nobody goes back and fixes all of the old tutorials. As a result JavaScript evolves but the answers you get when you search on google or stackoverflow can be from any date.

What if you are following some JavaScript tutorial and trying to understand some concepts. None of the tutorials ever state that JavaScript implementation is browser specific and environment specific. Yes … the various vendors are finally becoming similar but there are small differences. Afterall, the vendors are simply implementing ECMAScript.

You still see these differences in 2018. For example, if I go back to the same article as I linked above, the text expects you to see something like

> console.log(Dog.prototype);
{
    constructor: Dog(name) {
        if (name) { this.name = name; }
    },
    name: "Bubbles",
    speak: function() {
        return this.name + " says woof";
    },
    __proto__: Object { ... }
}

but what you see in most up-to-date firefox is

web developer tools output from firefox october 2018

whereas in chrome you see

web developer tools output from chrome october 2018

so my strategy my dear friend would be to understand the fundamentals. This way, you can adjust the syntax based on your environment. Unfortunately this will be so until all vendors catch up (if ever). Looking back on the past few years — I trully believed we would have it standardized by now.


Another thing, if you read the previous essay, that I wanted to improve my understanding in was the indirect invocation below

function Runner(name) {
  console.log(this instanceof Rabbit); // => true
  this.name = name;
}
function Rabbit(name, countLegs) {
  console.log(this instanceof Rabbit); // => true
  // Indirect invocation. Call parent constructor.
  Runner.call(this, name);
  this.countLegs = countLegs;
}
var myRabbit = new Rabbit('White Rabbit', 4);
myRabbit; // { name: 'White Rabbit', countLegs: 4 }

specifically

Runner.call(this, name);

Today I seem to have discovered that answer from the same article

The parent method will not be automatically called for you! The trick is that we can’t simply call Animal() directly because the context inside that function will not be correct. Calling a function like that would typically set this inside the function to point to the window object, our default context.

and if you recall JavaScript has several ways to invoke functions. It is important to understand because this is set during invocation. Thus, that is exactly how this type of function invocation in JavaScript works.

… Instead, we have to manually call the Animal constructor function while changing its context to point to our new Dog instance.

function Animal(age) {
    if (age) { this.age = age; }

    var alive = true;
    this.isAlive = function() { return alive; }
    this.die = function() { alive = false; }
}
Animal.prototype.age = 1;

function Dog(name) {
    if (name) { this.name = name; }
}
function Animal(age) { /* ... */ }
Animal.prototype.age = 1;

function Dog(name) { /* ... */ }

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.name = "Bubbles";
// The remainder of Dog.prototype members...

var v = new Dog("Vincent");

The key to understanding this relationship is understanding that the prototype object is a fall back mechanism.

[i]f the current instance object (v) does not have an age property directly on it JavaScript will “fall back” to the first prototype (Dog.prototype) and look for age there. If that object doesn’t have an age property, JavaScript will “fall back” to the next prototype, in this case Animal.prototype (defined by the __proto__ member of Dog.prototype). There it is! JavaScript found a member called age on the Animal.prototype and will use that value.

This structure is referred to as the prototype chain and falling back to successive prototypes is the mechanism by which JavaScript creates inheritance.


Polymorphism

But this is not exactly polymorphism since the two functions do not share a name or form (different method signatures). To show how JavaScript supports this concept we need another example.

Notice how the Animal object has an age property. This is great, but perhaps we want the age to always be represented in “human years” (which we’ll assume is the default).

So

Animal.prototype.getAge = function() { return this.age; }

and consequently

Dog.prototype.getAge = function() {
    var dogYears = Animal.prototype.getAge.apply(this);
    return (dogYears * 7);
}

Thus both Dog and Animal have getAge() but the functionality is a bit different. I’ll let the author explain as they do a good job

There are a couple things to note in the example above. First, we must use the method as it is defined on the Animal.prototype in order to call the parent method. If we try to simply call this.getAge() JavaScript will think we want the Dog.prototype.getAge method and we’ll enter a recursive, infinite loop! Second, we have to use the apply method of the getAge function object in order to switch the context again. Remember, if we were to simply call the method as is (Animal.prototype.getAge()) then the context will be the object on the left side of the dot: Animal.prototype. It will not be our Dog instance!

Once we have retrieved the stored age value, we can simply return that value multiplied by 7. In this manner we are able to achieve polymorphism by having a method with the same name and same function signature, but with different implementations depending on the type of object (Animal versus Dog versus Cat).

While we are able to write code that looks something like

class Dog extends Animal {
  constructor(name, age) {
    super(age);  // Call parent method of the same name
    if (name) { this._name = name; }
  }

  get name() {
    return this._name + " (the dog)";
  }

  set name(value) {
    this._name = value.toLowerCase();
  }

  speak() {
    return this.name + " says woof";
  }
}

It is nice to know the prototypical background of the language. It is the foundation of the language and how it fundamentally works. This way it does not matter which abstractions are built on top — you simply adjust =)

I had a lot of issues learning JavaScript as I was coming from a typical accredited computer science background. JavaScript is this frankenstein of a language that dominates the present software terrain. However, the varied implementation by vendors is less than ideal for its stability to teach new staff and overall well being of the language. I wish there was a better management of outdated information. JavaScript is constantly changing so I am not sure if this is possible in this never ending race.

Reminds me of the issues that people had surrounding learning Ruby and Ruby on Rails: the various syntactic magic that goes behind the scenes. I don’t think all of this magic is an issue in JavaScript environment for one big reason — JavaScript is free and all you need is a browser. Nobody to pay any fees; nothing to install; do not need to pay for an IDE. Plus, you get to take all of the invested development hours and use it for free.

Can’t say the same for Ruby on Rails or any other language or framework.

See you next time

Unless otherwise mentioned in the post, those projects are side projects which I work on on weekends and evenings, and are not affiliated with my work or employer.