Prototypical Inheritance - Writing Up

Prototypical inheritance - writing up

Constructor function introduction

You can use a function as a constructor to create objects, if the constructor function is named Person then the object(s) created with that constructor are instances of Person.

var Person = function(name){
this.name = name;
};
Person.prototype.walk=function(){
this.step().step().step();
};
var bob = new Person("Bob");

Person is the constructor function. When you create an instance using Person you have to use the new keyword:

var bob = new Person("Bob");console.log(bob.name);//=Bob
var ben = new Person("Ben");console.log(ben.name);//=Ben

The property/member name is instance specific, it's different for bob and ben

The member walk is part of Person.prototype and is shared for all instances bob and ben are instances of Person so they share the walk member (bob.walk===ben.walk).

bob.walk();ben.walk();

Because walk() could not be found on bob directly JavaScript will look for it in the Person.prototype as this is the constructor of bob. If it can't be found there it'll look on Object.prototype. This is called the prototype chain. The prototype part of inheritance is done by lengthening this chain; for example bob => Employee.prototype => Person.prototype => Object.prototype (more on inheritance later).

Even though bob, ben and all other created Person instances share walk the function will behave differently per instance because in the walk function it uses this. The value of this will be the invoking object; for now let's say it's the current instance so for bob.walk() "this" will be bob. (more on "this" and the invoking object later).

If ben was waiting for a red light and and bob was at a green light; then you'll invoke walk() on both ben and bob obviously something different would happen to ben and bob.

Shadowing members happens when we do something like ben.walk=22, even though bob and ben share walk the assignment of 22 to ben.walk will not affect bob.walk. This is because that statement will create a member called walk on ben directly and assign it a value of 22. There will be 2 different walk members: ben.walk and Person.prototype.walk.

When asking for bob.walk you'll get the Person.prototype.walk function because walk could not be found on bob. Asking for ben.walk however will get you the value 22 because the member walk has been created on ben and since JavaScript found walk on ben it will not look in the Person.prototype.

When using Object.create with 2 arguments, Object.defineProperty or Object.defineProperties shadowing works a bit different. More info on that here.

More about prototype

An object can inherit from another object through the use of prototype. You can set the prototype of any object with any other object using Object.create. In the constructor function introduction we have seen that if a member can't be found on the object then JavaScript will look in the prototpe chain for it.

In previous part we have seen that re assignment of members that come from an instance's prototype (ben.walk) will shadow that member (create walk on ben rather than changing Person.prototype.walk).

What if we don't re assign but mutate the member? Mutating is (for example) changing sub properties of an Object or invoking functions that will change the object's value. For example:

var o = [];
var a = o;
a.push(11);//mutate a, this will change o
a[1]=22;//mutate a, this will change o

The following code demonstrates the difference between prototype members and instance members by mutating members.

var person = {
name:"default",//immutable so can be used as default
sayName:function(){
console.log("Hello, I am "+this.name);
},
food:[]//not immutable, should be instance specific
// not suitable as prototype member
};
var ben = Object.create(person);
ben.name = "Ben";
var bob = Object.create(person);
console.log(bob.name);//=default, setting ben.name shadowed the member
// so bob.name is actually person.name
ben.food.push("Hamburger");
console.log(bob.food);//=["Hamburger"], mutating a shared member on the
// prototype affects all instances as it changes person.food
console.log(person.food);//=["Hamburger"]

The code above shows that ben and bob share members from person. There is only one person, it is set as bob's and ben's prototype (person is used as the first object in the prototype chain to look up requested members that don't exist on the instance). The problem with the above code is that bob and ben should have their own food member. This is where the constructor function comes in. It is used to create instance specific members. You could also pass arguments to it to set values of these instance specific members.

The next code shows another way to implement the constructor function, syntax is different but the idea is the same:

  1. Define an object that has members that will be same for many instances (person is a blueprint for bob and ben and can be for jilly, marie, clair ...)
  2. Define instance specific members that should be unique for instances (bob and ben).
  3. Create an instance running the code in step 2.

With constructor functions you'll set the prototype in step 2 in the following code we set the prototype in step 3.

In this code I have removed name from prototype as well as food because you are most likely going to shadow this almost immediately when creating an instance anyway. Name is now an instance specific member with a default value set in the constructor function. Becaus the food member is also moved from prototype to instance specific member it will not affect bob.food when adding food to ben.

var person = {
sayName:function(){
console.log("Hello, I am "+this.name);
},
//need to run the constructor function when creating
// an instance to make sure the instance has
// instance specific members
constructor:function(name){
this.name = name || "default";
this.food = [];
return this;
}
};
var ben = Object.create(person).constructor("Ben");
var bob = Object.create(person).constructor("Bob");
console.log(bob.name);//="Bob"
ben.food.push("Hamburger");
console.log(bob.food);//=[]

You may come across similar patterns that are more robust to help with object creation and object definition.

Inheritance

The following code shows how to inherit. The tasks are basically the same as in code before with a little extra

  1. Define instance specific members of an object (functions Hamster and RussionMini).
  2. Set the prototype part of inheritance (RussionMini.prototype = Object.create(Hamster.prototype))
  3. Define members that can be shared among instances.(Hamster.prototype and RussionMini.prototype)
  4. Create an instance running the code in step 1 and for objects that inherit have them run the Parent code as well (Hamster.apply(this,arguments);)

Using a pattern some would call "classical inheritance". If you are confused by the syntax I'll be happy to explain more or provide different patterns.

function Hamster(){
this.food=[];
}
function RussionMini(){
//Hamster.apply(this,arguments) executes every line of code
//in the Hamster body where the value of "this" is
//the to be created RussionMini (once for mini and once for betty)
Hamster.apply(this,arguments);
}
//setting RussionMini's prototype
RussionMini.prototype=Object.create(Hamster.prototype);
//setting the built in member called constructor to point
// to the right function (previous line has it point to Hamster)
RussionMini.prototype.constructor=RussionMini;
mini=new RussionMini();
//this.food (instance specic to mini)
// comes from running the Hamster code
// with Hamster.apply(this,arguments);
mini.food.push("mini's food");
//adding behavior specific to Hamster that will still be
// inherited by RussionMini because RussionMini.prototype's prototype
// is Hamster.prototype
Hamster.prototype.runWheel=function(){console.log("I'm running")};
mini.runWheel();//=I'm running

Object.create to set prototype part of inheritance

Here is the documentation about Object.create, it basically returns the second argument (not supported in the polyfil) with the first argument as the returned object's prototype.

If no second argument was given it'll return an empty object with first argument to be used as the returned object's prototype (the first object to be used in the returned object's prototype chain).

Some would set the prototype of RussionMini to an instance of Hamster (RussionMini.prototype = new Hamster()). This is not desirable because even though it accomplishes the same (RussionMini.prototype's prototype is Hamster.prototype) it also sets Hamster instance members as members of RussionMini.prototype. So RussionMini.prototype.food will exist but is a shared member (remember bob and ben in "More about prototype"?). The food member will be shadowed when creating a RussionMini because Hamster code is run with Hamster.apply(this,arguments); that in turn runs this.food = [] but any Hamster members will still be members of RussionMini.prototype.

Another reason could be that to create a Hamster a lot of complicated calculations need be done on passed arguments that may be not available yet, again you could pass in dummy arguments but it could unnecessarily complicate your code.

Extending and overriding Parent functions

Sometimes children need to extend parent functions.

You want the 'child' (=RussionMini) to do something extra. When RussionMini can call the Hamster code to do something and then do something extra you don't need to copy and paste Hamster code to RussionMini.

In the following example we assume that a Hamster can run 3km an hour but a Russion mini can only run half as fast. We can hard code 3/2 in RussionMini but if this value were to change we have multiple places in code where it needs changing. Here is how we use Hamster.prototype to get the parent (Hamster) speed.

var Hamster = function(name){
if(name===undefined){
throw new Error("Name cannot be undefined");
}
this.name=name;
}
Hamster.prototype.getSpeed=function(){
return 3;
}
Hamster.prototype.run=function(){
//Russionmini does not need to implement this function as
//it will do exactly the same as it does for Hamster
//But Russionmini does need to implement getSpeed as it
//won't return the same as Hamster (see later in the code)
return "I am running at " +
this.getSpeed() + "km an hour.";
}

var RussionMini=function(name){
Hamster.apply(this,arguments);
}
//call this before setting RussionMini prototypes
RussionMini.prototype = Object.create(Hamster.prototype);
RussionMini.prototype.constructor=RussionMini;

RussionMini.prototype.getSpeed=function(){
return Hamster.prototype
.getSpeed.call(this)/2;
}

var betty=new RussionMini("Betty");
console.log(betty.run());//=I am running at 1.5km an hour.

The disadvantage is that you hard code Hamster.prototype. There may be patterns that will give you the advantage of super as in Java.

Most of the patterns I've seen will either break when inheritance level is more than 2 levels (Child => Parent => GrandParent) or use more resources by implementing super through closures.

To override a Parent (=Hamster) method you do the same but don't do Hamster.prototype.parentMethod.call(this,....

this.constructor

The constructor property is included in the prototype by JavaScript, you can change it but it should point to the constructor function. So Hamster.prototype.constructor should point to Hamster.

If after setting prototype part of inheritance you should have it point to the right function again.

var Hamster = function(){};
var RussionMinni=function(){
// re use Parent constructor (I know there is none there)
Hamster.apply(this,arguments);
};
RussionMinni.prototype=Object.create(Hamster.prototype);
console.log(RussionMinni.prototype.constructor===Hamster);//=true
RussionMinni.prototype.haveBaby=function(){
return new this.constructor();
};
var betty=new RussionMinni();
var littleBetty=betty.haveBaby();
console.log(littleBetty instanceof RussionMinni);//false
console.log(littleBetty instanceof Hamster);//true
//fix the constructor
RussionMinni.prototype.constructor=RussionMinni;
//now make a baby again
var littleBetty=betty.haveBaby();
console.log(littleBetty instanceof RussionMinni);//true
console.log(littleBetty instanceof Hamster);//true

"Multiple inheritance" with mix ins

Some things are better not to be inherited, if a Cat can move and then a Cat should not inherit from Movable. A Cat is not a Movable but rather a Cat can move. In a class based language Cat would have to implement Movable. In JavaScript we can define Movable and define implementation here, Cat can either override, extend it or us it's default implementation.

For Movable we have instance specific members (like location). And we have members that are not instance specific (like the function move()). Instance specific members will be set by calling mxIns (added by mixin helper function) when creating an instance. Prototype members will be copied one by one on Cat.prototype from Movable.prototype using the mixin helper function.

var Mixin = function Mixin(args){
if(this.mixIns){
i=-1;len=this.mixIns.length;
while(++i<len){
this.mixIns[i].call(this,args);
}
}
};
Mixin.mix = function(constructor, mix){
var thing
,cProto=constructor.prototype
,mProto=mix.prototype;
//no extending, if multiple prototypes
// have members with the same name then use
// the last
for(thing in mProto){
if(Object.hasOwnProperty.call(mProto, thing)){
cProto[thing]=mProto[thing];
}
}
//instance intialisers
cProto.mixIns = cProto.mixIns || [];
cProto.mixIns.push(mix);
};
var Movable = function(args){
args=args || {};
//demo how to set defaults with truthy
// not checking validaty
this.location=args.location;
this.isStuck = (args.isStuck===true);//defaults to false
this.canMove = (args.canMove!==false);//defaults to true
//speed defaults to 4
this.speed = (args.speed===0)?0:(args.speed || 4);
};
Movable.prototype.move=function(){
console.log('I am moving, default implementation.');
};
var Animal = function(args){
args = args || {};
this.name = args.name || "thing";
};
var Cat = function(args){
var i,len;
Animal.call(args);
//if an object can have others mixed in
// then this is needed to initialise
// instance members
Mixin.call(this,args);
};
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Mixin.mix(Cat,Movable);
var poochie = new Cat({
name:"poochie",
location: {x:0,y:22}
});
poochie.move();

The above is a simple implementation that replaces same named functions with whatever mix in is mixed in last.

The this variable

In all the example code you'll see this referring to the current instance.

The this variable actually refers to the invoking object, it refers to the object that came before the function.

To clarify see the following code:

theInvokingObject.thefunction();

The instances where this would refer to the wrong object are usually when attaching event listeners, callbacks or timeouts and intervals. In the next 2 lines of code we pass the function, we don't invoke it. Passing the function is: someObject.aFunction and invoking it is: someObject.aFunction(). The this value does not refer to the object the function was declared on but on the object that invokes it.

setTimeout(someObject.aFuncton,100);//this in aFunction is window
somebutton.onclick = someObject.aFunction;//this in aFunction is somebutton

To make this in the above cases refer to someObject you can pass a closure instead of the function directly:

setTimeout(function(){someObject.aFuncton();},100);
somebutton.onclick = function(){someObject.aFunction();};

I like to define functions that return a function for closures on the prototype to have fine control over the variables that are included in the closure scope.

var Hamster = function(name){
var largeVariable = new Array(100000).join("Hello World");
// if I do
// setInterval(function(){this.checkSleep();},100);
// then largeVariable will be in the closure scope as well
this.name=name
setInterval(this.closures.checkSleep(this),1000);
};
Hamster.prototype.closures={
checkSleep:function(hamsterInstance){
return function(){
console.log(typeof largeVariable);//undefined
console.log(hamsterInstance);//instance of Hamster named Betty
hamsterInstance.checkSleep();
};
}
};
Hamster.prototype.checkSleep=function(){
//do stuff assuming this is the Hamster instance
};

var betty = new Hamster("Betty");

Passing (constructor) arguments

When Child calls a Parent (Hamster.apply(this,arguments);) we assume that Hamster uses the same arguments as RussionMini in the same order. For functions that call other functions I usually use another way to pass arguments.

I usually pass one object to a function and have that function mutate whatever it needs (set defaults), then that function will pass it to another function that will do the same and so on and so on. Here is an example:

//helper funciton to throw error
function thowError(message){
throw new Error(message)
};
var Hamster = function(args){
//make sure args is something so you get the errors
// that make sense to you instead of "args is undefined"
args = args || {};
//default value for type:
this.type = args.type || "default type";
//name is not optional, very simple truthy check f
this.name = args.name || thowError("args.name is not optional");
};
var RussionMini = function(args){
//make sure args is something so you get the errors
// that make sense to you instead of "args is undefined"
args = args || {};
args.type = "Russion Mini";
Hamster.call(this,args);
};
var ben = new RussionMini({name:"Ben"});
console.log(ben);// Object { type="Russion Mini", name="Ben"}
var betty = new RussionMini();//Error: args.name is not optional

This way of passing arguments in a function chain is useful in many cases. When you're working on code that would calculate a total of something and later you'd like to re factor the total of that something to be in a certain currency you may have to change a lot of functions to pass the value for currency. You could up scope a currency value (even to global like window.currency='USD') but that's a bad way to solve it.

With passing an object you could add currency to args whenever it's available in the function chain and mutate/use it whenever you need it without changing the other functions (explicitly have to pass it in the function calls).

Private variables

JavaScript doesn't have a private modifier.

I agree with the following: http://blog.millermedeiros.com/a-case-against-private-variables-and-functions-in-javascript/ and personally have not used them.

You can indicate to other programmers a member is meant to be private by naming it _aPrivate or putting all the private variables in an object variable called _.

You can implement private members through closures but instance specific private members can only be accessed by functions that are not on the prototype.

Not implementing privates as closures would leak implementation and enable you or users extending your code to use members that are not part of your public API. This can be both good and bad.

It's good because it enables you and others to mock certain members for testing easily. It gives others a chance to easily improve (patch) your code but this is also bad because there is no guarantee that a next version of your code has the same implementation and or private members.

By using closures you do not give others a choice and by using the naming convention with documentation you do. This is not specific to JavaScript, in other languages you can decide not to use private members as you trust others to know what they are doing and give them the choice to do as they want (with risks involved).

If you still insist on privates then the following pattern may help. It doesn't implement private though but implements protected.

Understanding of Javascript prototypal inheritance

  1. Yes, you cannot extend Array though so Array is a little different from your own functions.
  2. You could say objects inherrit from prototype up the prototype chain but you should not confuse it with inheritance as is in a class based language. More on prototype and constructor functions can be found here.

Note on 2: Instances created with the Animal constructor do not have Function up the prototype chain but the Animal constructor itself does have Function up it's prototype chain:

function Animal() {}
var a = new Animal();
console.log(a instanceof Function);//false
console.log(a instanceof Object);//true
console.log(Animal instanceof Function);//true
console.log(Animal instanceof Object);//true
var noProt = Object.create(null);
console.log(noProt instanceof Object);//false
console.log(noProt.hasOwnProperty);//undefined

All object instances (including Function) have Object in their prototype chain except when you use Object.create passing null as the first argument. To me this is like setting window.undefined to a value other than window.undefined as the assumption that every variable value in JS is an object goes out the window when someone does something like that.

Understanding a simple prototype inheritance example

Actually, your example (in this case) isn't better. You've defined properties and methods that are shared with all fruits (via the prototype), but not all fruits are yellow or have a sweetness of 7. In this case, these would make sense as passed arguments and defined in each instance (using this.color within your constructor).

So when would you choose one over the other? Let's go back to fruit - there are shared actions with fruits that we can do (for instance, eat and peel) - those could be methods of your prototype. These methods are defined once, and all instances refer to the same method.

Things that are unique (color, sweetness) make sense as instance properties (passed in via an argument).

As stated above, the other advantage of prototype methods is this: They're a single reference. Calling new Fruit() a thousand times will create a thousand instances of Fruit, but they all will reference that single prototype method (for example, eat).

Javascript prototypal inheritance - descendants override each other

Problem(s)

  • The Base class constructor is called once and only once.

    this.prototype = new baseClass;
  • Privileged methods will refer to the same this object across instances because those methods are created within the constructor (which was called only once).

Problem(s) based on a matter of opinion

  • You should try to avoid modifying native prototypes (ie. Function.prototype) if you plan on working alongside JavaScript that you do not own.

Solution

  • Call the constructor and parent constructor(s) for each new instance that is created.
  • Inherit the parent prototype chain (not a instance of a the parent class).
  • Maintain a 1:1 ratio of number of instances created to the number of calls the constructor(s) in the prototype chain.

Final solution to Max's problem

Please pay special attention to the inherits function and the ParentClass.call(this, title); line.
Constructors to look for are ParentClass and ChildClass

/**
* Allows a child constructor to safely inherit the parent constructors prototype chain.
* @type {Function}
* @param {!Function} childConstructor
* @param {!Function} parentConstructor
*/
function inherits(childConstructor, parentConstructor){
var TempConstructor = function(){};
TempConstructor.prototype = parentConstructor.prototype; // Inherit parent prototype chain

childConstructor.prototype = new TempConstructor(); // Create buffer object to prevent assignments directly to parent prototype reference.
childConstructor.prototype.constructor = childConstructor; // Reset the constructor property back the the child constructor
};

//////////////////////////////////////
/** @constructor */
function ParentClass(title) {
this.setTitle(title);

var randId_ = Math.random();
/** @return {number} */
this.getPrivlegedRandId = function()
{return randId_;};
};

/** @return {string} */
ParentClass.prototype.getTitle = function()
{return this.title_;};

/** @param {string} value */
ParentClass.prototype.setTitle = function(value)
{this.title_ = value;};

//////////////////////////////////////
/**
* @constructor
* @param {string} title
* @param {string} name
*/
ChildClass = function (name, title) {
ParentClass.call(this, title); // Call the parent class constructor with the required arguments

this.setName(name);
}
inherits(ChildClass, ParentClass); // Inherit the parent class prototype chain.

/** @return {string} */
ChildClass.prototype.getName = function()
{return this.name_;};

/** @param {string} value */
ChildClass.prototype.setName = function(value)
{this.name_ = value;};

Down the rabbit hole

For those who are curious why that works vs simply memorizing it the inherits function.

How properties are resolved using the prototype chain

When a property is not found at the instance level, JavaScript will try to resolve the missing property by searching through the instance constructors prototype chain. If the property is not found in the first prototype object, it will search the parent prototype object and so on all the way up to Object.prototype. If it can't find it within Object.prototype then an error will be thrown.

Calling the parent constructor from child constructor : Attempt #1

// Bad
var ChildConstructor = function(arg1, arg2, arg3){
var that = new ParentConstructor(this, arg1, arg2, arg3);
that.getArg1 = function(){return arg1};
return that;
}

Any varible that is created using new ChildConstructor will return an instance of ParentConstructor.
The ChildConstructor.prototype will be not be used.

Calling the parent constructor from child constructor : Attempt #2

// Good
var ChildConstructor = function(arg1, arg2, arg3){
ParentConstructor.call(this, arg1, arg2, arg3);
}

Now constructor and the parent constructor is called appropriately. However, only methods defined within the constructor(s) will exist. Properties on the parent prototypes will not be used because they have not yet been linked to the child constructors prototype.

Inheriting the parent prototype : Attempt #1

// Bad
ChildConstructor.prototype = new ParentConstructor();

The parent constructor will either be called only once or one too many times depending on whether or not ParentConstructor.call(this) is used.

Inheriting the parent prototype attempt #2

// Bad
ChildConstructor.prototype = ParentConstructor.prototype;

Though this technically works, any assignments to ChildConstructor.prototype will also be assigned to ParentConstructor.prototype because Objects are passed by reference and not by copy.

Inheriting the parent prototype attempt #3

// Almost there
var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();

This allows you to assign properties to ChildConstructor.prototype because it is an instance of a temporary anonymous function.
Properties that are not found on the instance of TempConstructor will then check it's prototype chain for the property, so you have successfully inherited the parent prototype. The only problem is that ChildConstructor.prototype.constructor is now pointing to TempConstructor.

Inheriting the parent prototype attempt #4

// Good
var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();
ChildConstructor.prototype.constructor = ChildConstructor;

All Together

var ParentConstructor = function(){
};


var ChildConstructor = function(){
ParentConstructor.call(this)
};

var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();
ChildConstructor.prototype.constructor = ChildConstructor;

You've successfully inherited from the parent class! Let's see if we can do better.

The inherits function

function inherits(childConstructor, parentConstructor){
var TempConstructor = function(){};
TempConstructor.prototype = parentConstructor.prototype; // Inherit parent prototype chain

childConstructor.prototype = new TempConstructor(); // Create buffer object to prevent assignments directly to parent prototype reference.
childConstructor.prototype.constructor = childConstructor; // Reset the constructor property back the the child constructor (currently set to TempConstructor )
};


var ParentConstructor = function(){
};


var ChildConstructor = function(){
ParentConstructor.call(this)
};
inherits(ChildConstructor, ParentConstructor);

Infinite prototypal inheritance in Javascript

Using more common style:

function P(){};
P.prototype = P;

In ECMA-262, the internal prototype property is denoted by [[Prototype]].

Assigning a different object to P.prototype does not modify P's [[Prototype]], so its inheritance chain r


Related Topics



Leave a reply



Submit