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 the call() or apply() method. This can be called stealing a constructor or inheritance by borrowing a constructor if you want to be more subtle about it.

The call() and apply() methods 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. However, you saw how to do this at the beginning of this chapter. You can redefine Triangle as follows:

    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); 

Here, we will create 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 

Borrowing a constructor and copying 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'; 

Lets test the following code:

   >var t = new Triangle(101); 
    >t.toString(); 
    "Triangle" 
    >t.id; 
    101 

No double inheritance:

    >typeoft.__proto__.id; 
    "undefined" 

The extend2() method also gives access to uber if needed:

    >t.uber.name; 
    "Shape" 
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.30.162