JavaScript Inheritance – How To Shoot Yourself In the Foot With Prototypes!

By Ryan Anklam

When learning JavaScript, many beginners find it difficult to grasp the intricate details of how JavaScript’s prototypical inheritance works. In this article I will take a look at how to properly use the prototypical inheritance model with parent functions that have instance properties.

A Simple Widget Object

The following code has a Widget parent class that has a messages property and a SubWidget class that uses Widget as it’s parent class. In this case we want each instance of the SubWidget to be initialized with an empty messages array:

var Widget = function( name ){
   this.messages = [];
};

Widget.prototype.type='Widget';

var SubWidget = function( name ){
  this.name = name;
  Widget.apply( this, Array.prototype.slice.call( arguments ) );
};

SubWidget.prototype = new Widget();

Before we set SubWidget’s prototype to a new instance of our Widget Prototype constructor, we get an object graph that looks like this:

JavaScriptPrototypes1

The final line of code sets SubWidget’s parent class to a new instance of the Widget class. Using the ”new” keyword starts to tie everything together by beginning to create the inheritance tree and tying the scope of our objects together. Our object graph now looks something like this:

JavaScriptPrototypes2

Do you see what the problem is yet? Lets create some instances of our subclass to highlight the issue:

var sub1 = new SubWidget( 'foo' );
var sub2 = new SubWidget( 'bar' );

sub1.messages.push( 'foo' ); 
sub2.messages.push( 'bar' );

Now our object graph looks like this:

JavaScriptPrototypes3

Before I talk about the real problem here I’d like to step back and talk about the “type” property on the widget’s constructor.  If it is not initialized by assignment each instance’s “type” property actually points to the constructor’s “type” property.  However, once it is initialized by assigning a value like so: sub1.type = 'Fuzzy Bunny' it becomes a property of the instance, as shown in the new object graph:

JavaScriptPrototypes4

Recognizing the Problem

Our bug should start to become clear now.  Let’s log the value of both sub1 and sub2’s messages array:

var Widget = function(){
   this.messages = [];
};

Widget.prototype.type='Widget';

var SubWidget = function( name ){
  this.name = name;
};

SubWidget.prototype = new Widget();

var sub1 = new SubWidget( 'foo' );
var sub2 = new SubWidget( 'bar' );

sub1.messages.push( 'foo' ); 
sub2.messages.push( 'bar' );

console.log( sub1.messages ); //[ 'foo', 'bar' ]
console.log( sub2.messages ); //[ 'foo', 'bar' ]

If you run this code and look at your console, you will see two instances reading [“foo”, “bar”] . Each object is sharing the same messages array!

Fixing the Problem

It would be tempting to fix this by adding another property to the SubWidget constructor like so:

var SubWidget = function( name ){
  this.name = name;
  this.messages = [];
};

However, what if we wanted to create other objects that extended Widget?  That new object would also need a messages array and pretty soon we have code that is a nightmare to maintain and extend. Additionally, what if we wanted to add other properties to the Widget constcutor that were initialized when instances of its sub-classes were constructed?  This isn’t very reusable or flexible solution.

In order to properly fix this all that needs to be done is to add a single line of code to our SubWidget constructor that will invoke the Widget constructor with the same scope of our SubWidget constructor. To do this we use the apply ()method which will give us the flexibility to add additional arguments to the SubWidget constructor without having to change the call to Widget:

var Widget = function(){
   this.messages = [];
};

Widget.prototype.type='Widget';

var SubWidget = function( name ){

  this.name = name;

  Widget.apply( this, Array.prototype.slice.call(arguments) );
};

SubWidget.prototype = new Widget();

By using the apply() method we are changing the context in which the messages array is created to the instance of the SubWidget. Now when we create new objects each instance has a new instance of the messages array:

var Widget = function( ){
   this.messages = [];
};

Widget.prototype.type='Widget';

var SubWidget = function( name ){

  this.name = name;
  Widget.apply( this, Array.prototype.slice.call( arguments ) );
};

SubWidget.prototype = new Widget();

var sub1 = new SubWidget( 'foo' );
var sub2 = new SubWidget( 'bar' );

sub1.messages.push( 'foo' );

sub2.messages.push( 'bar' );

console.log(sub1.messages); // ['foo']
console.log(sub2.messages); // ['bar']

Running this you will see [“foo”] and [“bar”] returned because our object instances now correctly have their own messages array. Now our object graph is correct:

JavaScriptPrototypes5

This post was originally published at https://blog.bittersweetryan.com/2013/05/javascript-inheritance-howto-shoot.html

Previous

Building a Game with In-App Payments for Firefox OS

Loading Images on Demand with Pure CSS

Next

18 thoughts on “JavaScript Inheritance – How To Shoot Yourself In the Foot With Prototypes!”

  1. Can you explain this line of code:

    Array.prototype.slice.call(this)

    In the next example “this” is replaced with “arguments” which makes a bit more sense to me.

    Thanks and great article!

  2. Very interesting article with nice graphs and presentation. The only question is what will happen if during execution we decide that our SubWidget shouldn’t inherit from Widget but from another object like “ChatWidget”. Then the prototype will be easy to change but the SubWidget is tightly coupled with Widget since we call apply during instantiation of “SubWidget”. Maybe a more robust approach and easier testable would be instead of :

    ` Widget.apply( this, Array.prototype.slice.call( arguments ) ); `

    to call it as :

    ` this.constructor.prototype.constructor.apply( this, Array.prototype.slice.call( arguments ) ); `

  3. This is a pretty tricky problem to get around indeed. Another solution that I’ve found very helpful (and more true to the classical inheritance model we see in other languages) is the one used (generated) by TypeScript (https://www.typescriptlang.org/). Basically, they define an inheritance function, __extends, as follows:
    var __extends = this.__extends || function (d, b) {
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
    };

    Now, the same example you showed above could be expressed with the following:

    // Base
    function Widget() {
    this.messages = [];
    }

    Widget.prototype = {
    type: ‘Widget’
    };

    // Derived
    var SubWidget = (function (_super) {
    __extends(SubWidget, _super);

    function SubWidget(name) {
    _super.call(this);
    this.name = name;
    }

    return SubWidget;
    })(Widget);

    While this syntax is a bit more verbose (keep in mind, it’s generated by TypeScript from a ECMA6 class declaration), it has the benefit of allowing parameters to be passed into the base constructor and avoiding having the base constructor being called to instantiate the derived prototype. It also works well with instanceof calls. Here’s a less trivial example:

    // Base Person class, takes a couple of parameters
    function Person(id, firstName, lastName) {
    this.id = id;
    this.firstName = firstName;
    this.lastName = lastName;
    // Can also do more complex initialization logic here since there’s no Student.prototype = new Person() call
    }

    Person.prototype = {
    toString: function () {
    return ‘Id: ‘ + this.id + ‘, FirstName: ‘ + this.firstName + ‘, LastName: ‘ + this.lastName;
    }
    };

    // Derived Student class, behaves like a classically defined class with super calls and all
    var Student = (function (_super) {
    __extends(Student, _super)

    function Student(id, firstName, lastName, gpa) {
    _super.call(this, id, firstName, lastName);
    this.gpa = gpa;
    }

    Student.prototype.toString = function () {
    return _super.prototype.toString.call(this) + ‘, Gpa: ‘ + this.gpa;
    };

    return Student;
    })(Person);

    // Calls will chain constructors like in classical inheritance
    var aPerson = new Person(1, ‘Bob’, ‘Builder’);
    var aStudent = new Student(2, ‘Joe’, ‘Schmoe’, 3.5);
    console.log(aStudent instanceof Person); // True

  4. Should type be pointing to prototype in diagram 4?

    Is there actually something wrong with the first code sample?

    Widget.apply( this, Array.prototype.slice.call(this) ); OR should we be sending arguments?

    I’m a bit confused about a number of things in this post.

    • Matthew, that is incorrect in the code sample, arguments is the correct er..argument. Perhaps the arrows are confusing in example 4, type belongs to Widget and SubWidget has a pointer to it.

  5. I guess there are some problems with the examples. On the first one, seems that code is already correct, as it is using `apply` passing the correct scope. And on the fifth one, shouldn’t it be `Widget.apply( this, Array.prototype.slice.call(arguments) );`?

    Visiting the original article, this was also pointed out in this comment: https://blog.bittersweetryan.com/2013/05/javascript-inheritance-howto-shoot.html?showComment=1370613761670#c5228254175426976768

  6. Yes. This blog post is nonsense. Experiment shows the bug it describes doesn’t happen. Each instance has its own messages array, as expected. And the snippets are wrong.

  7. I don’t understand the problem, the diagrams, or the solution:

    The very first diagram makes perfect sense, naturally, but wouldn’t the second diagram simply be a chart where the ‘prototype’ property of Widget draws an arrow directly to SubWidget (and, at the same time, SubWidget’s ‘__proto__’ property draws an arrow to Widget)?

    Additionally, while the solution works as you intended in the post, it seems to entirely defeat the purpose of inheritance. It looks like you ended up with two separate objects anyway — why wouldn’t you simply define two objects? If they need to share properties, use normal references (properties) to point at the shared object.

    From what I understand, the benefit of prototypal inheritance is similar to the benefits of classical inheritance: The ability to allocate less memory by choosing to “share” (extend) existing structured data. Since the data was only ever allocated once, it naturally “updates” the objects which extend it, if it changes on the source object (Class).

    Here’s the TL;DR example as I understand it… :

    // “Super-type”
    var Person = function() {
    this.what = function() {
    return this;
    };
    return this;
    };

    // Instance of ‘Person’
    var bob = new Person;

    // Extending ‘bob’
    bob.who = function() {
    return this.what(); //{bob}
    }

    // Extending ‘Person’
    Person.prototype.who = function() {
    return ‘idk’; //”idk”
    }

    // Type extension
    Person.prototype.isPerson = function() {
    return true;
    };

    // Results
    Person.isPerson(); //true
    bob.isPerson(); //true
    Person.who(); //”idk”
    bob.who(); //{bob}

    /* … */

    // Proxies (an alternative)
    var Travel = {
    toPlace: function(p) {
    this.location = p;
    return p;
    },
    withVehicle: function(v) {
    if(!this.vehicles)
    this.vehicles = [];
    this.vehicles.push(v);
    return this;
    }
    };

    var destination = Travel.withVehicle(‘ship’).toPlace(‘Mars’);

    console.log(destination); //”Mars”
    /* With proxies, there is no need to “extend” the properties to a sub-type. Instead, invoking objects can simply leverage the proxy API (like we do with jQuery, underscore, etc.) */

    I wrote this on my phone… Hope it works! Someone please correct me if my understanding is wrong.

  8. The only “problem” I see is that you’ve attempted to use ES3 style “inheritance” which will simply flatten the prototype, which is never what you want to do.

    function Widget(name) {
    this.name = name || “anonymous”;
    this.messages = [];
    }

    function SubWidget(name) {
    Widget.apply(this, arguments);
    }

    // This creates a fresh object from the Widget.prototype object.
    // Doin’ it right, FTW.
    SubWidget.prototype = Object.create(Widget.prototype);
    SubWidget.prototype.constructor = SubWidget;

    var subA = new SubWidget(“a”);
    var subB = new SubWidget(“b”);

    subA.messages.push(1,2,3,4);
    subB.messages.push(5,6,7,8);

    console.log( subA );
    /*
    SubWidget {
    name: “a”,
    messages: [1,2,3,4]
    }
    */

    console.log( subB );
    /*
    SubWidget {
    name: “b”,
    messages: [5,6,7,8]
    }
    */

  9. Hi, Great article but I have one question, as I am a little puzzled.

    Could you please explain?

    In the first section of the article, you said this “Before we set SubWidget’s prototype to a new instance of our Widget Prototype constructor, we get an object graph that looks like this:”, and when viewing the graph, you can clearly see no properties are being shared between each object.

    With that said, could you please explain what this line is doing;

    Widget.apply( this, Array.prototype.slice.call( arguments ) );

    I am completely confused by this, and I was wondering if this is necessary for the prototypical inheritance at all?

    Thanks in advance,

    B

  10. One of the most commonly used inheritance in JavaScript is Combination Inheritance (Prototype Chaining + Constructor stealing). Neither Prototype Chaining nor Constructor stealing should be used on their own, if used it will cause unexpected results as shown in the article.

    By Prototype Chaining I mean,
    SubWidget.prototype = new Widget();
    By Constructor stealing I mean,
    Widget.apply( this, Array.prototype.slice.call( arguments ) );

Comments are closed.