Inheritance - Object-Oriented JavaScript Second Edition (2013)

Object-Oriented JavaScript Second Edition (2013)

Chapter 6. Inheritance

If you go back to Chapter 1, Object-oriented JavaScript and review the Object-oriented programming section, you'll see that you already know how to apply most of them to JavaScript. You know what objects, methods, and properties are. You know that there are no classes in JavaScript, although you can achieve the same using constructor functions. Encapsulation? Yes, the objects encapsulate both the data and the means (methods) to do something with the data. Aggregation? Sure, an object can contain other objects. In fact, this is almost always the case since methods are functions, and functions are also objects.

Now, let's focus on the inheritance part. This is one of the most interesting features, as it allows you to reuse existing code, thus promoting laziness, which is likely to be what brought human species to computer programming in the first place.

JavaScript is a dynamic language and there is usually more than one way to achieve any given task. Inheritance is not an exception. In this chapter, you'll see some common patterns for implementing inheritance. Having a good understanding of these patterns will help you pick the right one, or the right mix, depending on your task, project or your style.

Prototype chaining

Let's start with the default way of implementing inheritance—inheritance chaining through the prototype.

As you already know, every function has a prototype property, which points to an object. When a function is invoked using the new operator, an object is created and returned. This new object has a secret link to the prototype object. The secret link (called __proto__ in some environments) allows methods and properties of the prototype object to be used as if they belonged to the newly-created object.

The prototype object is just a regular object and, therefore, it also has the secret link to its prototype. And so a chain is created, called a prototype chain:

Prototype chaining

In this illustration, an object A contains a number of properties. One of the properties is the hidden __proto__ property, which points to another object, B. B's __proto__ property points to C. This chain ends with the Object.prototype object—the grandparent, and every object inherits from it.

This is all good to know, but how does it help you? The practical side is that when object A lacks a property but B has it, A can still access this property as its own. The same applies if B also doesn't have the required property, but C does. This is how inheritance takes place: an object can access any property found somewhere down the inheritance chain.

Throughout the rest of this chapter, you'll see different examples that use the following hierarchy: a generic Shape parent is inherited by a 2D shape, which in turn is inherited by any number of specific two-dimensional shapes such as a Triangle, Rectangle, and so on.

Prototype chaining example

Prototype chaining is the default way to implement inheritance. In order to implement the hierarchy, let's define three constructor functions.

function Shape(){

this.name = 'Shape';

this.toString = function () {

return this.name;

};

}

function TwoDShape(){

this.name = '2D shape';

}

function Triangle(side, height){

this.name = 'Triangle';

this.side = side;

this.height = height;

this.getArea = function () {

return this.side * this.height / 2;

};

}

The code that performs the inheritance magic is as follows:

TwoDShape.prototype = new Shape();

Triangle.prototype = new TwoDShape();

What's happening here? You take the object contained in the prototype property of TwoDShape and instead of augmenting it with individual properties, you completely overwrite it with another object, created by invoking the Shape() constructor with new. The same forTriangle: its prototype is replaced with an object created by new TwoDShape(). It's important to remember that JavaScript works with objects, not classes. You need to create an instance using the new Shape() constructor and after that you can inherit its properties; you don't inherit from Shape() directly. Additionally, after inheriting, you can modify the Shape() constructor, overwrite it, or even delete it, and this will have no effect on TwoDShape, because all you needed is one instance to inherit from.

As you know from the previous chapter, overwriting the prototype (as opposed to just adding properties to it), has side effects on the constructor property. Therefore, it's a good idea to reset the constructor after inheriting:

TwoDShape.prototype.constructor = TwoDShape;

Triangle.prototype.constructor = Triangle;

Now, let's test what has happened so far. Creating a Triangle object and calling its own getArea() method works as expected:

>var my = new Triangle(5, 10);

>my.getArea();

25

Although the my object doesn't have its own toString() method, it inherited one and you can call it. Note, how the inherited method toString() binds the this object to my.

>my.toString();

"Triangle"

It's fascinating to consider what the JavaScript engine does when you call my.toString():

· It loops through all of the properties of my and doesn't find a method called toString().

· It looks at the object that my.__proto__ points to; this object is the instance new TwoDShape() created during the inheritance process.

· Now, the JavaScript engine loops through the instance of TwoDShape and doesn't find a toString() method. It then checks the __proto__ of that object. This time __proto__ points to the instance created by new Shape().

· The instance of new Shape() is examined and toString() is finally found.

· This method is invoked in the context of my, meaning that this points to my.

If you ask my, "who's your constructor?" it reports it correctly because of the reset of the constructor property after the inheritance:

>my.constructor === Triangle;

true

Using the instanceof operator you can validate that my is an instance of all three constructors.

> my instanceof Shape;

true

> my instanceofTwoDShape;

true

> my instanceof Triangle;

true

> my instanceof Array;

false

The same happens when you call isPropertyOf()on the constructors passing my:

>Shape.prototype.isPrototypeOf(my);

true

>TwoDShape.prototype.isPrototypeOf(my);

true

>Triangle.prototype.isPrototypeOf(my);

true

>String.prototype.isPrototypeOf(my);

false

You can also create objects using the other two constructors. Objects created with new TwoDShape() also get the method toString(), inherited from Shape().

>var td = new TwoDShape();

>td.constructor === TwoDShape;

true

>td.toString();

"2D shape"

>var s = new Shape();

>s.constructor === Shape;

true

Moving shared properties to the prototype

When you create objects using a constructor function, own properties are added using this. This could be inefficient in cases where properties don't change across instances. In the previous example, Shape() was defined like so:

function Shape(){

this.name = 'Shape';

}

This means that every time you create a new object using new Shape() a new name property is created and stored somewhere in the memory. The other option is to have the name property added to the prototype and shared among all the instances:

function Shape() {}

Shape.prototype.name = 'Shape';

Now, every time you create an object using new Shape(), this object doesn't get its own property name, but uses the one added to the prototype. This is more efficient, but you should only use it for properties that don't change from one instance to another. Methods are ideal for this type of sharing.

Let's improve on the preceding example by adding all methods and suitable properties to the prototype. In the case of Shape() and TwoDShape() everything is meant to be shared:

// constructor

function Shape() {}

// augment prototype

Shape.prototype.name = 'Shape';

Shape.prototype.toString = function () {return this.name;};

// another constructor

function TwoDShape() {}

// take care of inheritance

TwoDShape.prototype = new Shape();

TwoDShape.prototype.constructor = TwoDShape;

// augment prototype

TwoDShape.prototype.name = '2D shape';

As you can see, you have to take care of inheritance first before augmenting the prototype. Otherwise anything you add to TwoDShape.prototype gets wiped out when you inherit.

The Triangle constructor is a little different, because every object it creates is a new triangle, which is likely to have different dimensions. So it's good to keep side and height as own properties and share the rest. The method getArea(), for example, is the same regardless of the actual dimensions of each triangle. Again, you do the inheritance bit first and then augment the prototype.

function Triangle(side, height) {

this.side = side;

this.height = height;

}

// take care of inheritance

Triangle.prototype = new TwoDShape();

Triangle.prototype.constructor = Triangle;

// augment prototype

Triangle.prototype.name = 'Triangle';

Triangle.prototype.getArea = function () {

return this.side * this.height / 2;

};

All the preceding test code work exactly the same, for example:

>var my = new Triangle(5, 10);

>my.getArea();

25

>my.toString();

"Triangle"

There is only a slight behind-the-scenes difference when calling my.toString(). The difference is that there is one more lookup to be done before the method is found in the Shape.prototype, as opposed to in the new Shape() instance like it was in the previous example.

You can also play with hasOwnProperty() to see the difference between the own property versus a property coming down the prototype chain.

>my.hasOwnProperty('side');

true

>my.hasOwnProperty('name');

false

The calls to isPrototypeOf() and the instanceof operator from the previous example work exactly the same:

>TwoDShape.prototype.isPrototypeOf(my);

true

> my instanceof Shape;

true

Inheriting the prototype only

As explained previously, for reasons of efficiency you should add the reusable properties and methods to the prototype. If you do so, then it's a good idea to inherit only the prototype, because all the reusable code is there. This means that inheriting theShape.prototype object is better than inheriting the object created with new Shape(). After all, new Shape() only gives you own shape properties that are not meant to be reused (otherwise they would be in the prototype). You gain a little more efficiency by:

· Not creating a new object for the sake of inheritance alone

· Having less lookups during runtime (when it comes to searching for toString() for example)

Here's the updated code; the changes are highlighted:

function Shape() {}

// augment prototype

Shape.prototype.name = 'Shape';

Shape.prototype.toString = function () {

return this.name;

};

function TwoDShape() {}

// take care of inheritance

TwoDShape.prototype = Shape.prototype;

TwoDShape.prototype.constructor = TwoDShape;

// augment prototype

TwoDShape.prototype.name = '2D shape';

function Triangle(side, height) {

this.side = side;

this.height = height;

}

// take care of inheritance

Triangle.prototype = TwoDShape.prototype;

Triangle.prototype.constructor = Triangle;

// augment prototype

Triangle.prototype.name = 'Triangle';

Triangle.prototype.getArea = function () {return this.side * this.height / 2;};

The test code gives you the same result:

>var my = new Triangle(5, 10);

>my.getArea();

25

>my.toString();

"Triangle"

What's the difference in the lookups when calling my.toString()? First, as usual, the JavaScript engine looks for a method toString() of the my object itself. The engine doesn't find such a method, so it inspects the prototype. The prototype turns out to be pointing to the same object that the prototype of TwoDShape points to and also the same object that Shape.prototype points to. Remember, that objects are not copied by value, but only by reference. So the lookup is only a two-step process as opposed to four (in the previous example) or three (in the first example).

Simply copying the prototype is more efficient but it has a side effect: because all the prototypes of the children and parents point to the same object, when a child modifies the prototype, the parents get the changes, and so do the siblings.

Look at this line:

Triangle.prototype.name = 'Triangle';

It changes the name property, so it effectively changes Shape.prototype.name too. If you create an instance using new Shape(), its name property says "Triangle":

>var s = new Shape();

>s.name;

"Triangle"

This method is more efficient but may not suit all your use cases.

A temporary constructor – new F()

A solution to the previously outlined problem, where all prototypes point to the same object and the parents get children's properties, is to use an intermediary to break the chain. The intermediary is in the form of a temporary constructor function. Creating an empty function F() and setting its prototype to the prototype of the parent constructor, allows you to call new F() and create objects that have no properties of their own, but inherit everything from the parent's prototype.

Let's take a look at the modified code:

function Shape() {}

// augment prototype

Shape.prototype.name = 'Shape';

Shape.prototype.toString = function () {

return this.name;

};

function TwoDShape() {}

// take care of inheritance

var F = function () {};

F.prototype = Shape.prototype;

TwoDShape.prototype = new F();

TwoDShape.prototype.constructor = TwoDShape;

// augment prototype

TwoDShape.prototype.name = '2D shape';

function Triangle(side, height) {

this.side = side;

this.height = height;

}

// take care of inheritance

var F = function () {};

F.prototype = TwoDShape.prototype;

Triangle.prototype = new F();

Triangle.prototype.constructor = Triangle;

// augment prototype

Triangle.prototype.name = 'Triangle';

Triangle.prototype.getArea = function () {return this.side * this.height / 2;};

Creating my triangle and testing the methods:

>var my = new Triangle(5, 10);

>my.getArea();

25

>my.toString();

"Triangle"

Using this approach, the prototype chain stays in place:

>my.__proto__ === Triangle.prototype;

true

>my.__proto__.constructor === Triangle;

true

>my.__proto__.__proto__ === TwoDShape.prototype;

true

>my.__proto__.__proto__.__proto__.constructor === Shape;

true

And also the parents' properties are not overwritten by the children:

>var s = new Shape();

>s.name;

"Shape"

>"I am a " + new TwoDShape(); // calling toString()

"I am a 2D shape"

At the same time, this approach supports the idea that only properties and methods added to the prototype should be inherited, and own properties should not. The rationale behind this is that own properties are likely to be too specific to be reusable.

Uber – access to the parent from a child object

Classical OO languages usually have a special syntax that gives you access to the parent class, also referred to as superclass. This could be convenient when a child wants to have a method that does everything the parent's method does plus something in addition. In such cases, the child calls the parent's method with the same name and works with the result.

In JavaScript, there is no such special syntax, but it's trivial to achieve the same functionality. Let's rewrite the last example and, while taking care of inheritance, also create an uber property that points to the parent's prototype object.

function Shape() {}

// augment prototype

Shape.prototype.name = 'Shape';

Shape.prototype.toString = function () {

varconst = this.constructor;

returnconst.uber

? this.const.uber.toString() + ', ' + this.name

: this.name;

};

function TwoDShape() {}

// take care of inheritance

var F = function () {};

F.prototype = Shape.prototype;

TwoDShape.prototype = new F();

TwoDShape.prototype.constructor = TwoDShape;

TwoDShape.uber = Shape.prototype;

// augment prototype

TwoDShape.prototype.name = '2D shape';

function Triangle(side, height) {

this.side = side;

this.height = height;

}

// take care of inheritance

var F = function () {};

F.prototype = TwoDShape.prototype;

Triangle.prototype = new F();

Triangle.prototype.constructor = Triangle;

Triangle.uber = TwoDShape.prototype;

// augment prototype

Triangle.prototype.name = 'Triangle';

Triangle.prototype.getArea = function () {return this.side * this.height / 2;};

The new things here are:

· A newuber property points to the parent's prototype

· The updated toString()method

Previously, toString() only returned this.name. Now, in addition to that, there is a check to see whether this.constructor.uber exists and, if it does, call its toString() first. this.constructor is the function itself, and this.constructor.uber points to the parent's prototype. The result is that when you call toString() for a Triangle instance, all toString() methods up the prototype chain are called:

>var my = new Triangle(5, 10);

>my.toString();

"Shape, 2D shape, Triangle"

The name of the property uber could've been "superclass" but this would suggest that JavaScript has classes. Ideally it could've been "super" (as in Java), but "super" is a reserved word in JavaScript. The German word "über" suggested by Douglass Crockford, means more or less the same as "super" and, you have to admit, it sounds uber-cool.

Isolating the inheritance part into a function

Let's move the code that takes care of all of the inheritance details from the last example into a reusable extend() function:

function extend(Child, Parent) {

var F = function () {};

F.prototype = Parent.prototype;

Child.prototype = new F();

Child.prototype.constructor = Child;

Child.uber = Parent.prototype;

}

Using this function (or your own custom version of it) helps you keep your code clean with regard to the repetitive inheritance-related tasks. This way you can inherit by simply using:

extend(TwoDShape, Shape);

and

extend(Triangle, TwoDShape);

Let's see a complete example:

// inheritance helper

function extend(Child, Parent) {

var F = function () {};

F.prototype = Parent.prototype;

Child.prototype = new F();

Child.prototype.constructor = Child;

Child.uber = Parent.prototype;

}

// define -> augment

function Shape() {}

Shape.prototype.name = 'Shape';

Shape.prototype.toString = function () {

return this.constructor.uber

? this.constructor.uber.toString() + ', ' + this.name

: this.name;

};

// define -> inherit -> augment

function TwoDShape() {}

extend(TwoDShape, Shape);

TwoDShape.prototype.name = '2D shape';

// define

function Triangle(side, height) {

this.side = side;

this.height = height;

}

// inherit

extend(Triangle, TwoDShape);

// augment

Triangle.prototype.name = 'Triangle';

Triangle.prototype.getArea = function () {

return this.side * this.height / 2;

};

Testing:

> new Triangle().toString();

"Shape, 2D shape, Triangle"

Copying properties

Now, let's try a slightly different approach. Since inheritance is all about reusing code, can you simply copy the properties you like from one object to another? Or from a parent to a child? Keeping the same interface as the preceding extend() function, you can create a function extend2() which takes two constructor functions and copies all of the properties from the parent's prototype to the child's prototype. This will, of course, carry over methods too, as methods are just properties that happen to be functions.

function extend2(Child, Parent) {

var p = Parent.prototype;

var c = Child.prototype;

for (vari in p) {

c[i] = p[i];

}

c.uber = p;

}

As you can see, a simple loop through the properties is all it takes. As with the previous example, you can set an uber property if you want to have handy access to parent's methods from the child. Unlike the previous example though, it's not necessary to reset theChild.prototype.constructor because here the child prototype is augmented, not overwritten completely, so the constructor property points to the initial value.

This method is a little inefficient compared to the previous method because properties of the child prototype are being duplicated instead of simply being looked up via the prototype chain during execution. Bear in mind that this is only true for properties containing primitive types. All objects (including functions and arrays) are not duplicated, because these are passed by reference only.

Let's see an example of using two constructor functions, Shape() and TwoDShape(). The Shape() function's prototype object contains a primitive property, name, and a non-primitive one—the toString()method:

var Shape = function () {};

varTwoDShape = function () {};

Shape.prototype.name = 'Shape';

Shape.prototype.toString = function () {

return this.uber

? this.uber.toString() + ', ' + this.name

: this.name;

};

If you inherit with extend(), neither the objects created with TwoDShape() nor its prototype get an own name property, but they have access to the one they inherit.

> extend(TwoDShape, Shape);

>var td = new TwoDShape();

>td.name;

"Shape"

>TwoDShape.prototype.name;

"Shape"

>td.__proto__.name;

"Shape"

>td.hasOwnProperty('name');

false

> td.__proto__.hasOwnProperty('name');

false

But if you inherit with extend2(), the prototype of TwoDShape()gets its own copy of the name property. It also gets its own copy of toString(), but it's a reference only, so the function will not be recreated a second time.

>extend2(TwoDShape, Shape);

>var td = new TwoDShape();

> td.__proto__.hasOwnProperty('name');

true

> td.__proto__.hasOwnProperty('toString');

true

> td.__proto__.toString === Shape.prototype.toString;

true

As you can see, the two toString() methods are the same function object. This is good because it means that no unnecessary duplicates of the methods are created.

So, you can say that extend2() is less efficient than extend() because it recreates the properties of the prototype. But, this is not so bad because only the primitive data types are duplicated. Additionally, this is beneficial during the prototype chain lookups as there are fewer chain links to follow before finding the property.

Take a look at the uber property again. This time, for a change, it's set on the Parent object's prototype p, not on the Parent constructor. This is why toString() uses it as this.uber, as opposed to this.constructor.uber. This is just an illustration that you can shape your favorite inheritance pattern in any way you see fit. Let's test it out:

>td.toString();

"Shape, Shape"

TwoDShape didn't redefine the name property, hence the repetition. It can do that at any time and (the prototype chain being live) all the instances "see" the update:

>TwoDShape.prototype.name = "2D shape";

>td.toString();

"Shape, 2D shape"

Heads-up when copying by reference

The fact that objects (including functions and arrays) are copied by reference could sometimes lead to results you don't expect.

Let's create two constructor functions and add properties to the prototype of the first one:

> function Papa() {}

>function Wee() {}

>Papa.prototype.name = 'Bear';

>Papa.prototype.owns = ["porridge", "chair", "bed"];

Now, let's have Wee inherit from Papa (either extend() or extend2() will do):

>extend2(Wee, Papa);

Using extend2(), the Wee function's prototype inherited the properties of Papa.prototype as its own.

>Wee.prototype.hasOwnProperty('name');

true

>Wee.prototype.hasOwnProperty('owns');

true

The name property is primitive so a new copy of it is created. The property owns is an array object so it's copied by reference:

>Wee.prototype.owns;

["porridge", "chair", "bed"]

>Wee.prototype.owns=== Papa.prototype.owns;

true

Changing the Wee function's copy of name doesn't affect Papa:

>Wee.prototype.name += ', Little Bear';

"Bear, Little Bear"

>Papa.prototype.name;

"Bear"

Changing the Wee function's owns property, however, affects Papa, because both properties point to the same array in memory.

>Wee.prototype.owns.pop();

"bed"

>Papa.prototype.owns;

["porridge", "chair"]

It's a different story when you completely overwrite the Wee function's copy of owns with another object (as opposed to modifying the existing one). In this case Papa.owns keeps pointing to the old object, while Wee.owns points to a new one.

>Wee.prototype.owns= ["empty bowl", "broken chair"];

>Papa.prototype.owns.push('bed');

>Papa.prototype.owns;

["porridge", "chair", "bed"]

Think of an object as something that is created and stored in a physical location in memory. Variables and properties merely point to this location, so when you assign a brand new object to Wee.prototype.owns you essentially say, "Hey, forget about this other old object, move your pointer to this new one instead".

The following diagram illustrates what happens if you imagine the memory being a heap of objects (like a wall of bricks) and you point to (refer to) some of these objects.

· A new object is created and A points to it.

· A new variable B is created and made equal to A, meaning it now points to the same place where A is pointing to.

· A property color is changed using the B handle (pointer). The brick is now white. A check for A.color === "white" would be true.

· A new object is created and the B variable/pointer is recycled to point to that new object. A and B are now pointing to different parts of the memory pile, they have nothing in common and changes to one of them don't affect the other:

Heads-up when copying by reference

If you want to address the problem that objects are copied by reference, consider a deep copy, described further.

Objects inherit from objects

All of the examples so far in this chapter assume that you create your objects with constructor functions and you want objects created with one constructor to inherit properties that come from another constructor. However, you can also create objects without the help of a constructor function, just by using the object literal and this is, in fact, less typing. So how about inheriting those?

In Java or PHP, you define classes and have them inherit from other classes. That's why you'll see the term classical, because the OO functionality comes from the use of classes. In JavaScript, there are no classes, so programmers that come from a classical background resort to constructor functions because constructors are the closest to what they are used to. In addition, JavaScript provides the new operator, which can further suggest that JavaScript is like Java. The truth is that, in the end, it all comes down to objects. The first example in this chapter used this syntax:

Child.prototype = new Parent();

Here, the Child constructor (or class, if you will) inherits from Parent. But this is done through creating an object using new Parent() and inheriting from it. That's why this is also referred to as a pseudo-classical inheritance pattern, because it resembles classical inheritance, although it isn't (no classes are involved).

So why not get rid of the middleman (the constructor/class) and just have objects inherit from objects? In extend2() the properties of the parent prototype object were copied as properties of the child prototype object. The two prototypes are in essence just objects. Forgetting about prototypes and constructor functions, you can simply take an object and copy all of its properties into another object.

You already know that objects can start as a "blank canvas" without any own properties by using var o = {}; and then get properties later. But, instead of starting fresh, you can start by copying all of the properties of an existing object. Here's a function that does exactly that: it takes an object and returns a new copy of it.

function extendCopy(p) {

var c = {};

for (vari in p) {

c[i] = p[i];

}

c.uber = p;

return c;

}

Simply copying all of the properties is a straightforward pattern, and it's widely used. Let's see this function in action. You start by having a base object:

var shape = {

name: 'Shape',

toString: function () {

return this.name;

}

};

In order to create a new object that builds upon the old one, you can call the function extendCopy() which returns a new object. Then, you can augment the new object with additional functionality.

vartwoDee = extendCopy(shape);

twoDee.name = '2D shape';

twoDee.toString = function () {

return this.uber.toString() + ', ' + this.name;

};

A triangle object that inherits the 2D shape object:

var triangle = extendCopy(twoDee);

triangle.name = 'Triangle';

triangle.getArea = function () {

return this.side * this.height / 2;

};

Using the triangle:

>triangle.side = 5;

>triangle.height = 10;

>triangle.getArea();

25

>triangle.toString();

"Shape, 2D shape, Triangle"

A possible drawback of this method is the somewhat verbose way of initializing the new triangle object, where you manually set values for side and height, as opposed to passing them as values to a constructor. But, this is easily resolved by having a function, for example, called init() (or __construct() if you come from PHP) that acts as a constructor and accepts initialization parameters. Or, have extendCopy() accept two parameters: an object to inherit from and another object literal of properties to add to the copy before it's returned, in other words just merge two objects.

Deep copy

The function extendCopy(), discussed previously, creates what is called a shallow copy of an object, just like extend2() before that. The opposite of a shallow copy would be, naturally, a deep copy. As discussed previously (in the Heads-up when copying by referencesection ), when you copy objects you only copy pointers to the location in memory where the object is stored. This is what happens in a shallow copy. If you modify an object in the copy, you also modify the original. The deep copy avoids this problem.

The deep copy is implemented in the same way as the shallow copy: you loop through the properties and copy them one by one. But, when you encounter a property that points to an object, you call the deep copy function again:

function deepCopy(p, c) {

c = c || {};

for (vari in p) {

if (p.hasOwnProperty(i)) {

if (typeof p[i] === 'object') {

c[i] = Array.isArray(p[i]) ? [] : {};

deepCopy(p[i], c[i]);

} else {

c[i] = p[i];

}

}

}

return c;

}

Let's create an object that has arrays and a sub-object as properties.

var parent = {

numbers: [1, 2, 3],

letters: ['a', 'b', 'c'],

obj: {

prop: 1

},

bool: true

};

Let's test this by creating a deep copy and a shallow copy. Unlike the shallow copy, when you update the numbers property of a deep copy, the original is not affected.

>varmydeep = deepCopy(parent);

>varmyshallow = extendCopy(parent);

>mydeep.numbers.push(4,5,6);

6

>mydeep.numbers;

[1, 2, 3, 4, 5, 6]

>parent.numbers;

[1, 2, 3]

>myshallow.numbers.push(10);

4

>myshallow.numbers;

[1, 2, 3, 10]

>parent.numbers;

[1, 2, 3, 10]

>mydeep.numbers;

[1, 2, 3, 4, 5, 6]

Two side notes about the deepCopy() function:

· Filtering out non-own properties with hasOwnProperty() is always a good idea to make sure you don't carry over someone's additions to the core prototypes.

· Array.isArray() exists since ES5 because it's surprisingly hard otherwise to tell real arrays from objects. The best cross-browser solution (if you need to define isArray() in ES3 browsers) looks a little hacky, but it works:

· if (Array.isArray !== "function") {

· Array.isArray = function (candidate) {

· return

· Object.prototype.toString.call(candidate) ===

· '[object Array]';

· };

}

object()

Based on the idea that objects inherit from objects, Douglas Crockford advocates the use of an object() function that accepts an object and returns a new one that has the parent as a prototype.

function object(o) {

function F() {}

F.prototype = o;

return new F();

}

If you need access to an uber property, you can modify the object() function like so:

function object(o) {

var n;

function F() {}

F.prototype = o;

n = new F();

n.uber = o;

return n;

}

Using this function is the same as using the extendCopy(): you take an object such as twoDee, create a new object from it and then proceed to augmenting the new object.

var triangle = object(twoDee);

triangle.name = 'Triangle';

triangle.getArea = function () {

return this.side * this.height / 2;

};

The new triangle still behaves the same way:

>triangle.toString();

"Shape, 2D shape, Triangle"

This pattern is also referred to as prototypal inheritance , because you use a parent object as the prototype of a child object. It's also adopted and built upon in ES5 and called Object.create(). For example:

>var square = Object.create(triangle);

Using a mix of prototypal inheritance and copying properties

When you use inheritance, you will most likely want to take already existing functionality and then build upon it. This means creating a new object by inheriting from an existing object and then adding additional methods and properties. You can do this with one function call, using a combination of the last two approaches just discussed.

You can:

· Use prototypal inheritance to use an existing object as a prototype of a new one

· Copy all of the properties of another object into the newly created one

· function objectPlus(o, stuff) {

· var n;

· function F() {}

· F.prototype = o;

· n = new F();

· n.uber = o;

·

· for (vari in stuff) {

· n[i] = stuff[i];

· }

· return n;

}

This function takes an object o to inherit from and another object stuff that has the additional methods and properties that are to be copied. Let's see this in action.

Start with the base shape object:

var shape = {

name: 'Shape',

toString: function () {

return this.name;

}

};

Create a 2D object by inheriting shape and adding more properties. The additional properties are simply created with an object literal.

vartwoDee = objectPlus(shape, {

name: '2D shape',

toString: function () {

return this.uber.toString() + ', ' + this.name;

}

});

Now, let's create a triangle object that inherits from 2D and adds more properties.

var triangle = objectPlus(twoDee, {

name: 'Triangle',

getArea: function () {return this.side * this.height / 2;},

side: 0,

height: 0

});

Testing how it all works by creating a concrete triangle my with defined side and height:

var my = objectPlus(triangle, {

side: 4, height: 4

});

>my.getArea();

8

>my.toString();

"Shape, 2D shape, Triangle, Triangle"

The difference here, when executing toString(), is that the Triangle name is repeated twice. That's because the concrete instance was created by inheriting triangle, so there was one more level of inheritance. You could give the new instance a name:

>objectPlus(triangle, {

side: 4,

height: 4,

name: 'My 4x4'

}).toString();

"Shape, 2D shape, Triangle, My 4x4"

This objectPlus() is even closer to ES5's Object.create() only the ES5 one takes the additional properties (the second argument) using something called property descriptors (discussed in Appendix C, Built-in Objects).

Multiple inheritance

Multiple inheritance is where a child inherits from more than one parent. Some OO languages support multiple inheritance out of the box, and some don't. You can argue both ways: that multiple inheritance is convenient, or that it's unnecessary, complicates application design, and it's better to use an inheritance chain instead. Leaving the discussion of multiple inheritance's pros and cons for the long, cold winter nights, let's see how you can do it in practice in JavaScript.

The implementation can be as simple as taking the idea of inheritance by copying properties, and expanding it so that it takes an unlimited number of input objects to inherit from.

Let's create a multi() function that accepts any number of input objects. You can wrap the loop that copies properties in another loop that goes through all the objects passed as arguments to the function.

function multi() {

var n = {}, stuff, j = 0, len = arguments.length;

for (j = 0; j <len; j++) {

stuff = arguments[j];

for (vari in stuff) {

if (stuff.hasOwnProperty(i)) {

n[i] = stuff[i];

}

}

}

return n;

}

Let's test this by creating three objects: shape, twoDee, and a third, unnamed object. Then, creating a triangle object means calling multi() and passing all three objects.

var shape = {

name: 'Shape',

toString: function () {

return this.name;

}

};

vartwoDee = {

name: '2D shape',

dimensions: 2

};

var triangle = multi(shape, twoDee, {

name: 'Triangle',

getArea: function () {

return this.side * this.height / 2;

},

side: 5,

height: 10

});

Does this work? Let's see. The method getArea() should be an own property, dimensions should come from twoDee and toString() from shape.

>triangle.getArea();

25

>triangle.dimensions;

2

>triangle.toString();

"Triangle"

Bear in mind that multi() loops through the input objects in the order they appear and if it happens that two of them have the same property, the last one wins.

Mixins

You might come across the term mixin. Think of a mixin as an object that provides some useful functionality but is not meant to be inherited and extended by sub-objects. The approach to multiple inheritance outlined previously can be considered an implementation of the mixins idea. When you create a new object you can pick and choose any other objects to mix into your new object. By passing them all to multi() you get all their functionality without making them part of the inheritance tree.

Parasitic inheritance

If you like the fact that you can have all kinds of different ways to implement inheritance in JavaScript, and you're hungry for more, here's another one. This pattern, courtesy of Douglas Crockford, is called parasitic inheritance. It's about a function that creates objects by taking all of the functionality from another object into a new one, augmenting the new object, and returning it, "pretending that it has done all the work".

Here's an ordinary object, defined with an object literal, and unaware of the fact that it's soon going to fall victim to parasitism:

vartwoD = {

name: '2D shape',

dimensions: 2

};

A function that creates triangle objects could:

· Use twoD object as a prototype of an object called that (similar to this for convenience). This can be done in any way you saw previously, for example using the object() function or copying all the properties.

· Augment that with more properties.

· Return that.

· function triangle(s, h) {

· var that = object(twoD);

· that.name ='Triangle';

· that.getArea = function () {return this.side * this.height / 2;};

· that.side = s;

· that.height = h;

· return that;

}

Because triangle() is a normal function, not a constructor, it doesn't require the new operator. But because it returns an object, calling it with new by mistake works too.

>var t = triangle(5, 10);

>t.dimensions;

2

>vart2 = new triangle(5,5);

>t2.getArea();

12.5

Note, that that is just a name; it doesn't have a special meaning, the way this does.

Borrowing a constructor

One more way of implementing inheritance (the last one in the chapter, I promise) has to do again with constructor functions, and not the objects directly. In this pattern the constructor of the child calls the constructor of the parent using either call() or apply()methods. This can be called stealing a constructor, or inheritance by borrowing a constructor if you want to be more subtle about it.

call() and apply() were discussed in Chapter 4, Objects but here's a refresher: they allow you to call a function and pass an object that the function should bind to its this value. So for inheritance purposes, the child constructor calls the parent's constructor and binds the child's newly-created this object as the parent's this.

Let's have this parent constructor Shape():

function Shape(id) {

this.id = id;

}

Shape.prototype.name = 'Shape';

Shape.prototype.toString = function () {return this.name;};

Now, let's define Triangle() which uses apply() to call the Shape() constructor, passing this (an instance created with new Triangle()) and any additional arguments.

function Triangle() {

Shape.apply(this, arguments);

}

Triangle.prototype.name = 'Triangle';

Note, that both Triangle() and Shape()have added some extra properties to their prototypes.

Now, let's test this by creating a new triangle object:

>var t = new Triangle(101);

>t.name;

"Triangle"

The new triangle object inherits the id property from the parent, but it doesn't inherit anything added to the parent's prototype:

>t.id;

101

>t.toString();

"[object Object]"

The triangle failed to get the Shape function's prototype properties because there was never a new Shape() instance created, so the prototype was never used. But, you saw how to do this at the beginning of this chapter. You can redefine Triangle like this:

function Triangle() {

Shape.apply(this, arguments);

}

Triangle.prototype = new Shape();

Triangle.prototype.name = 'Triangle';

In this inheritance pattern, the parent's own properties are recreated as the child's own properties. If a child inherits an array or other object, it's a completely new value (not a reference) and modifying it won't affect the parent.

The drawback is that the parent's constructor gets called twice: once with apply() to inherit own properties and once with new to inherit the prototype. In fact the own properties of the parent are inherited twice. Let's take this simplified scenario:

function Shape(id) {

this.id = id;

}

function Triangle() {

Shape.apply(this, arguments);

}

Triangle.prototype = new Shape(101);

Creating a new instance:

>var t = new Triangle(202);

>t.id;

202

There's an own property id, but there's also one that comes down the prototype chain, ready to shine through:

>t.__proto__.id;

101

> delete t.id;

true

>t.id;

101

Borrow a constructor and copy its prototype

The problem of the double work performed by calling the constructor twice can easily be corrected. You can call apply() on the parent constructor to get all own properties and then copy the prototype's properties using a simple iteration (or extend2() as discussed previously).

function Shape(id) {

this.id = id;

}

Shape.prototype.name = 'Shape';

Shape.prototype.toString = function () {

return this.name;

};

function Triangle() {

Shape.apply(this, arguments);

}

extend2(Triangle, Shape);

Triangle.prototype.name = 'Triangle';

Testing:

>var t = new Triangle(101);

>t.toString();

"Triangle"

>t.id;

101

No double inheritance:

>typeoft.__proto__.id;

"undefined"

extend2() also gives access to uber if needed:

>t.uber.name;

"Shape"

Summary

In this chapter you learned quite a few ways (patterns) for implementing inheritance and the following table summarizes them. The different types can roughly be divided into:

· Patterns that work with constructors

· Patterns that work with objects

You can also classify the patterns based on whether they:

· Use the prototype

· Copy properties

· Do both (copy properties of the prototype)

#

Name

Example

Classification

Notes

1

Prototype chaining

(pseudo-classical)

Child.prototype = new Parent();

· Works with constructors

· Uses the prototype chain

· The default mechanism.

· Tip: move all properties/methods that are meant to be reused to the prototype, add the non-reusable as own properties.

2

Inherit only the prototype

Child.prototype = Parent.prototype;

· Works with constructors

· Copies the prototype (no prototype chain, all share the same prototype object)

· More efficient, no new instances are created just for the sake of inheritance.

· Prototype chain lookup during runtime- is fast, since there's no chain.

· Drawback: children can modify parents' functionality.

3

Temporary constructor

function extend(Child, Parent) {

var F = function(){};

F.prototype = Parent.prototype;

Child.prototype = new F();

Child.prototype.constructor = Child;

Child.uber = Parent.prototype;

}

· Works with constructors

· Uses the prototype chain

· Unlike #1, it only inherits properties of the prototype. Own properties (created with this inside the constructor) are not inherited.

· Provides convenient access to the parent (through uber).

4

Copying the prototype properties

function extend2(Child, Parent) {

var p = Parent.prototype;

var c = Child.prototype;

for (vari in p) {

c[i] = p[i];

}

c.uber = p;

}

· Works with constructors

· Copies properties

· Uses the prototype chain

· All properties of the parent prototype become properties of the child prototype

· No need to create a new object only for inheritance purposes

· Shorter prototype chains

5

Copy all properties

(shallow copy)

function extendCopy(p) {

var c = {};

for (vari in p) {

c[i] = p[i];

}

c.uber = p;

return c;

}

· Works with objects

· Copies properties

· Simple

· Doesn't use prototypes

6

Deep copy

Same as above, but recurse into objects

· Works with objects

· Copies properties

Same as #5 but clones objects and arrays

7

Prototypal inheritance

function object(o){

function F() {}

F.prototype = o;

return new F();

}

· Works with objects

· Uses the prototype chain

· No pseudo-classes, objects inherit from objects

· Leverages the benefits of the prototype

8

Extend and augment

function objectPlus(o, stuff) {

var n;

function F() {}

F.prototype = o;

n = new F();

n.uber = o;

for (vari in stuff) {

n[i] = stuff[i];

}

return n;

}

· Works with objects

· Uses the prototype chain

· Copies properties

· Mix of prototypal inheritance (#7) and copying properties (#5)

· One function call to inherit and extend at the same time

9

Multiple inheritance

function multi() {

var n = {}, stuff, j = 0,

len = arguments.length;

for (j = 0; j <len; j++) {

stuff = arguments[j];

for (vari in stuff) {

n[i] = stuff[i];

}

}

return n;

}

· Works with objects

· Copies properties

· A mixin-style implementation

· Copies all the properties of all the parent objects in the order of appearance

10

Parasitic inheritance

function parasite(victim) {

var that = object(victim);

that.more = 1;

return that;

}

· Works with objects

· Uses the prototype chain

· Constructor-like function creates objects

· Copies an object, augments and returns the copy

11

Borrowing constructors

function Child() {

Parent.apply(this, arguments);

}

Works with constructors

· Inherits only own properties

· Can be combined with #1 to inherit the prototype too

· Convenient way to deal with the issues when a child inherits a property that is an object (and therefore passed by reference)

12

Borrow a constructor and copy the prototype

function Child() {

Parent.apply(this, arguments);

}

extend2(Child, Parent);

· Works with constructors

· Uses the prototype chain

· Copies properties

· Combination of #11 and #4

· Allows you to inherit both own properties and prototype properties without calling the parent constructor twice

Given so many options, you must be wondering: which is the right one? That depends on your style and preferences, your project, task, and team. Are you more comfortable thinking in terms of classes? Then pick one of the methods that work with constructors. Are you going to need just one or a few instances of your "class"? Then choose an object-based pattern.

Are these the only ways of implementing inheritance? No. You can chose a pattern from the preceding table or you can mix them, or you can think of your own. The important thing is to understand and be comfortable with objects, prototypes, and constructors; the rest is just pure joy.

Case study – drawing shapes

Let's finish off this chapter with a more practical example of using inheritance. The task is to be able to calculate the area and the perimeter of different shapes, as well as to draw them, while reusing as much code as possible.

Analysis

Let's have one Shape constructor that contains all of the common parts. From there, let's have Triangle, Rectangle, and Square constructors, all inheriting from Shape. A square is really a rectangle with the same-length sides, so let's reuse Rectangle when building theSquare.

In order to define a shape, you'll need points with x and y coordinates. A generic shape can have any number of points. A triangle is defined with three points, a rectangle (to keep it simpler)—with one point and the lengths of the sides. The perimeter of any shape is the sum of its sides' lengths. Calculating the area is shape-specific and will be implemented by each shape.

The common functionality in Shape would be:

· A draw() method that can draw any shape given the points

· A getParameter() method

· A property that contains an array of points

· Other methods and properties as needed

For the drawing part let's use a <canvas> tag. It's not supported in early IEs, but hey, this is just an exercise.

Let's have two other helper constructors—Point and Line. Point will help when defining shapes; Line will make calculations easier, as it can give the length of the line connecting any two given points.

You can play with a working example here: http://www.phpied.com/files/canvas/. Just open your console and start creating new shapes as you'll see in a moment.

Implementation

Let's start by adding a canvas tag to a blank HTML page:

<canvas height="600" width="800" id="canvas" />

Then, put the JavaScript code inside <script> tags:

<script>

// ... code goes here

</script>

Now, let's take a look at what's in the JavaScript part. First, the helper Point constructor. It just can't get any more trivial than this:

function Point(x, y) {

this.x = x;

this.y = y;

}

Bear in mind that the coordinates of the points on the canvas start from x=0, y=0, which is the top left. The bottom right will be x = 800, y = 600:

Implementation

Next, the Line constructor. It takes two points and calculates the length of the line between them, using the Pythagorean Theorem a2 + b2 = c2 (imagine a right-angled triangle where the hypotenuse connects the two given points).

function Line(p1, p2) {

this.p1 = p1;

this.p2 = p2;

this.length = Math.sqrt(

Math.pow(p1.x - p2.x, 2) +

Math.pow(p1.y - p2.y, 2)

);

}

Next, comes the Shape constructor. The shapes will have their points (and the lines that connect them) as own properties. The constructor also invokes an initialization method, init(), that will be defined in the prototype.

function Shape() {

this.points = [];

this.lines= [];

this.init();

}

Now the big part: the methods of Shape.prototype. Let's define all of these methods using the object literal notation. Refer to the comments for guidelines as to what each method does.

Shape.prototype = {

// reset pointer to constructor

constructor: Shape,

// initialization, sets this.context to point

// to the context if the canvas object

init: function () {

if (this.context === undefined) {

var canvas = document.getElementById('canvas');

Shape.prototype.context = canvas.getContext('2d');

}

},

// method that draws a shape by looping through this.points

draw: function () {

vari, ctx = this.context;

ctx.strokeStyle = this.getColor();

ctx.beginPath();

ctx.moveTo(this.points[0].x, this.points[0].y);

for (i = 1; i<this.points.length; i++) {

ctx.lineTo(this.points[i].x, this.points[i].y);

}

ctx.closePath();

ctx.stroke();

},

// method that generates a random color

getColor: function () {

vari, rgb = [];

for (i = 0; i< 3; i++) {

rgb[i] = Math.round(255 * Math.random());

}

return 'rgb(' + rgb.join(',') + ')';

},

// method that loops through the points array,

// creates Line instances and adds them to this.lines

getLines: function () {

if (this.lines.length> 0) {

return this.lines;

}

vari, lines = [];

for (i = 0; i<this.points.length; i++) {

lines[i] = new Line(this.points[i],

this.points[i + 1] || this.points[0]);

}

this.lines = lines;

return lines;

},

// shell method, to be implemented by children

getArea: function () {},

// sums the lengths of all lines

getPerimeter: function () {

vari, perim = 0, lines = this.getLines();

for (i = 0; i<lines.length; i++) {

perim += lines[i].length;

}

return perim;

}

};

Now, the children constructor functions. Triangle first:

function Triangle(a, b, c) {

this.points = [a, b, c];

this.getArea = function () {

var p = this.getPerimeter(),

s = p / 2;

return Math.sqrt(

s

* (s - this.lines[0].length)

* (s - this.lines[1].length)

* (s - this.lines[2].length));

};

}

The Triangle constructor takes three point objects and assigns them to this.points (its own collection of points). Then it implements the getArea() method, using Heron's formula:

Area = s(s-a)(s-b)(s-c)

s is the semi-perimeter (perimeter divided by two).

Next, comes the Rectangle constructor. It receives one point (the upper-left point) and the lengths of the two sides. Then, it populates its points array starting from that one point.

function Rectangle(p, side_a, side_b){

this.points = [

p,

new Point(p.x + side_a, p.y),// top right

new Point(p.x + side_a, p.y + side_b), // bottom right

new Point(p.x, p.y + side_b)// bottom left

];

this.getArea = function () {

return side_a * side_b;

};

}

The last child constructor is Square. A square is a special case of a rectangle, so it makes sense to reuse Rectangle. The easiest thing to do here is to borrow the constructor.

function Square(p, side){

Rectangle.call(this, p, side, side);

}

Now that all constructors are done, let's take care of inheritance. Any pseudo-classical pattern (one that works with constructors as opposed to objects) will do. Let's try using a modified and simplified version of the prototype-chaining pattern (the first method described in this chapter). This pattern calls for creating a new instance of the parent and setting it as the child's prototype. In this case, it's not necessary to have a new instance for each child—they can all share it.

(function () {

var s = new Shape();

Triangle.prototype = s;

Rectangle.prototype = s;

Square.prototype = s;

})();

Testing

Let's test this by drawing shapes. First, define three points for a triangle:

>varp1 = new Point(100, 100);

>varp2 = new Point(300, 100);

>varp3 = new Point(200, 0);

Now, you can create a triangle by passing the three points to the Triangle constructor:

>var t = new Triangle(p1, p2, p3);

You can call the methods to draw the triangle on the canvas and get its area and perimeter:

>t.draw();

>t.getPerimeter();

482.842712474619

>t.getArea();

10000.000000000002

Now, let's play with a rectangle instance:

>var r = new Rectangle(new Point(200, 200), 50, 100);

>r.draw();

>r.getArea();

5000

>r.getPerimeter();

300

And finally, a square:

>var s = new Square(new Point(130, 130), 50);

>s.draw();

>s.getArea();

2500

>s.getPerimeter();

200

It's fun to draw these shapes. You can also be as lazy as the following example, which draws another square, reusing a triangle's point:

> new Square(p1, 200).draw();

The result of the tests will be something like this:

Testing

Exercises

1. Implement multiple inheritance but with a prototypal inheritance pattern, not property copying. For example:

2. var my = objectMulti(obj, another_obj, a_third, {

3. additional: "properties"

});

The property additional should be an own property, all the rest should be mixed into the prototype.

4. Use the canvas example to practice. Try out different things, for example:

· Draw a few triangles, squares, and rectangles.

· Add constructors for more shapes, such as Trapezoid, Rhombus, Kite, and Pentagon. If you want to learn more about the canvas tag, create a Circle constructor too. It will need to overwrite the draw() method of the parent.

· Can you think of another way to approach the problem and use another type of inheritance?

· Pick one of the methods that uses uber as a way for a child to access its parent. Add functionality where the parents can keep track of who their children are. Perhaps by using a property that contains a children array?