Prototype and Inheritance in JS (non-class)

https://www.digitalocean.com/community/tutorials/understanding-prototypes-and-inheritance-in-javascript

Creating objects through Constructor Functions

Because each character will share many characteristics, such as having a name, and a level, we use a constructor functions to create templates for those common traits of each hero.

Every hero has a name, and a certain level of experience

We have created a constructor function called Hero with two parameters: name and level. Since every character will have a name and a level, it makes sense for each new character to have these properties.

The this keyword will refer to the new instance that is created, so setting this.name to the name parameter ensures the new object will have a name property set.

The hierarchy looks like this:

The Prototype Object

Whenever we create a constructor function, JS will automatically create a literal object that acts as the prototype object.

That literal object’s sole purpose is to contain functions and properties for all instantiations of your constructor functions.

Note that this object (like all objects of JS) derives from Object, and will have its __proto__ pointing to Object’s Prototype Object.

This literal object acts as the prototype object for Hero. It will also have a constructor property pointing back to your constructor function. Thus, making this prototype object the same type as your constructor function.

In our case, we create a constructor function “Hero” with its properties. JS gives us an empty literal object (Let’s call it Prototype Object) in order to act as a single object that keeps properties and functions that are shared among all instances of Hero.

Note that our Hero Prototype Object derives from Object and thus, has its __proto__ referencing Object’s Prototype Object.

It then creates and assigns a “constructor” property from the Hero Prototype Object to your constructor function. This makes the prototype object type Hero. Finally, it assigns the “prototype” property from your constructor property onto the “Hero Prototype Object”.

Creating an Instance

What this means is that any instantiations of Hero will have its OWN properties and functions from the Constructor function.

hence if we were to make three hero objects, hero1, hero2, and hero3, they all have their own unique properties of name, and level.

i.e

hero1 is “Grom”, level 1
hero2 is “Haomarush”, level 2
hero3 is “Thrall”, level 8

However, they ALL share the “Hero Prototype object”.

So if the “Hero Prototype object” has a property “nickname” initiated to “Orc”, then they would all have nickname = “Orc”.

Same goes for any functions and other properties that “Hero Prototype Object” may have.

Let’s check on how this works. First we display the prototype of our object hero1. You can do it in 2 ways:


output:

Hero {}
Hero {}

Now repeat with hero2, hero3. You’ll see that their __proto__ all are Hero{}. They all point to the same Prototype Object Hero{}

Adding to the Prototype

Let’s add a property nickname to the prototoype, and see what it looks like:

Now our “Hero Prototype Object” will look like this:

Hero { nickname: ‘orc’ }

This means that when we try to read a property from a Hero object, say from hero1,
– it will try to look for “nickname” in hero1 first.
– When it does not find it, it will go up the hierarchy into the prototype object, which it will then find.

If you were to change nickname:

You cannot change it from the instantiation

Simply put, don’t confuse yourself when you try to change a property or function of a prototype object.

You cannot change it through an instantiation like this:

Erroneously, many people may think that it will see if nickname exist in the instantiation, it does not. Then it goes up to the prototype and finds it there. Then it just assigns the new string.

When it comes to setting values, JS does not let you access at the prototype level. It only let’s you read at the prototype level if the property does not exist at the object level.

If you want to set the prototype object to a new value, you must do so through Object.prototype.YourPropertyName.

All of our heroes must be able to greet amicably. Let’s create a function to do so:

Now, all heroes will be able to say hello.

Different character classes of heroes

However, each hero has different abilities. Some wield different weapons. All have vastly different skills and abilities.

It wouldn’t make sense to put all the abilities for every class into the Hero constructor, because different classes will have different abilities.

We want to create new constructor functions, but we also want them to be connected to the original Hero.

Let’s take a look at how we can accomplish this with prototype inheritance and constructors.

The Warrior

We use call in order to chain constructors. Essentially, call replaces a function’s this reference to a passed in object.
Hence, we replace Hero’s constructor function’s this reference to point to Warrior’s this. Then, any kind of initialization done in Hero will take place in Warrior. In other words:

  • We first create a constructor function called Warrior. This identifies Warrior.
  • We then pass the “this” reference to Hero via function call. Using Warrior’s “this” reference, we start to construct it like a Hero. Essentially, we are doing chain constructors for Warrior. We want to first initialize Warrior to be a Hero with Hero’s properties and functions.
  • Then, we come back to Warrior, and initialize Warrior’s properties.

note: The JavaScript call() Method

The call() method is a predefined JavaScript function method.

It can be used to invoke (call) a function with an owner object as the first argument (parameter).
In our example, instance person calls fullName. However, fullName’s this is myObject.

With call(), you can use a method belonging to another object.

This example calls the fullName function of person, but is using it on myObject:

In the extended object Warrior, we initialize Warrior with Hero’s properties via javascript’s call function.

So in the same way, we call Hero’s constructor, but with Warrior’s this.
We pass Warrior’s this into Hero’ constructor

The Healer

Same as Warrior.

Both constructors of Warrior and Healer now have the properties of Hero and their own unique ones.

We’ll add the attack() method to Warrior because its what they do. We want all instances of Warrior to be able to attack, as they should.

All instances of Healer should be able to heal, because its their specialty. Thus, we create the “heal” function so that all future instances of Healer will be able to call heal.

Linking up the Prototype

When you create Warriors, it will be setup in a similar fashion like Hero. You’ll get a Warrior Prototype Object. Your Warrior’s prototype reference will point to Warrior Prototype Object. Warrior Prototype Object will add and point “constructor” back to your Warrior.

Since Hero’s prototype properties and methods are not automatically linked when you use call() to chain constructors, our Warrior will use Object.create() to link the prototypes, making sure to put it before any additional methods are created and added to the prototype like so:

Note:
The Object.create() method creates a new object, using an existing object to provide the newly created object’s __proto__

Object.create

We have class names’s prototype point to a literal object to denote that all
all instances of this class’s __proto__ should point to this literal object
for prototype functionalities. Since Warrior’s prototype now points to literal object
w (which also has __proto__ pointing to Hero Prototype object), this means all instances
of warriors have prototype functionalities on w, and if not found, goes to Hero Prototype Object.

That is why greet will work.

Take note that variable w is the Prototype Object for Warrior. Its pointing to Prototype Object Hero. Hence,

Prototype objects are simply single objects linked together by __proto__. In other words, the Prototype Object A chains to Prototype Object B via Object.create(…). Object.create(…) creates a new object, using an existing object to provide the newly created object’s __proto__ .

When their instances of their classes do not find it i the object, it goes to the prototype object. If it doesn’t find it in that prototype object, it will try to access prototype object’s __proto__, going up the chain.

Now, all instances of Warrior can not only attack, but also greet you as well! Because greet is a prototype function of Hero.

Double Prototype Level

Now let’s create a special class called Mage, where we can heal like a Healer, but also have our own Mage special ability.

Structure

You’ll see that an instance of the Mage will inherit properties and functions of its deriving object Warrior, and its deriving object Hero, and Object.

Furthermore, it will be able to use the whole hierarchy of its own prototype, which includes Warrior, Hero, and Object.


— Structure —

Mage {
name: ‘Thrall’,
level: 99,
weapon: ‘Ragnorak’,
special: ‘summons Bahamut’ }

Mage { constructor: [Function: Mage] }

Healer { constructor: [Function: Healer], heal: [Function] }

Hero { greet: [Function] }

{}

Custom Example

Image Object diagram

output:

Image railay-beach, accessible at: http://localhost:8080/railay-beach.jpg. Created at Fri Apr 13 2018 18:12:24 GMT+0800 (CST)
Image tiger-temple-budda, accessible at: http://localhost:8080/budda.jpg. Created at Fri Apr 13 2018 18:12:24 GMT+0800 (CST)
Image { print: [Function] }
Image { print: [Function] }
{}
{}

Pictorial Object diagram

1) Create custom constructor function
2) Create custom Prototype Object via Object.create. This creates an empty object with prototype of your choice.
3) Check by calling base prototype’s function via call().

4) Connect Prototype Object with your custom constructor function.
5) Instantiate, and call base prototype functionalities for testing.


output:
This place is great!
Description should animate from -300 y (off screen) to middle of screen
Image beautiful-place, accessible at: http://locahost:8080/beautiful-place.jpg. Created at Mon Apr 16 2018 11:06:29 GMT+0800 (CST)


Image southpaw, accessible at: localhost:8080/southpaw.jpg. Created at Mon Apr 16 2018 11:06:29 GMT+0800 (CST)
cover format depending on fashion, fitness, food

CoverArticle object diagram