Inheritance Antipattern 20

Michael Bolin wrote an excellent blog post about the inheritance antipattern that is gaining a lot of foothold among JavaScript developers these days. The post also links to an article giving a lot more depth on the topic.

When I attended The Ajax Experience 2009, I saw a number of “misguided” things that people were doing with JavaScript. [snip].. I wanted to get up and yell, “Stop — you’re all doing it wrong!”

Although I agree with almost everything Michael writes I think it is worth pointing out some things.

Background

For those too lazy to read Michael’s post and article here is an example of the classic inheritance pattern as well as the functional inheritance pattern. This example is intentionally very simple.

Classic inheritance pattern

function Phone(phoneNumber) {
  this.phoneNumber_ = phoneNumber;
};

Phone.prototype.getPhoneNumber = function() {
  return this.phoneNumber_;
};

Functional inheritance pattern

function Phone(phoneNumber) {
  var that = {};
  that.getPhoneNumber = function() {
    return phoneNumber;
  };
  return that;
};

Compilation

Michael argues that the functional pattern is not good because methods cannot be inlined and the end result is much larger. He also says that it uses more memory. I think it is important to realize that it uses a LOT more memory and is significantly slower. Given a class with 1 methods It is about 100 times slower in Chrome, 20 times slower in Safari and about 10 times slower in Firefox.

Prototype object literal

Michael also mentions the following pattern:

function Phone(phoneNumber) {
  this.phoneNumber_ = phoneNumber;
}
Phone.prototype = {
  getPhoneNumber: function() {
    return this.phoneNumber_;
  }
};

I like this pattern but it has one serious drawback. It cannot be used to extend existing classes because in that case the protytype must be an instance of the class you are inheriting from.

If you do not care about IE support this can be done by using __proto__ like this:

function SmartPhone(phoneNumber) {
  Phone.call(this, phoneNumber);
}
SmartPhone.prototype = {
  __proto__: Phone.prototype,
  sendEmail: function(email) {
    ...
  }
};

Semantics

I understand why people like Douglas Crockford preaches the functional inheritance pattern. Due to its closure the local variable is truly private and this is important when you are doing mashups and other security sensitive code. However, when it comes to building large scale applications like Gmail you cannot afford this extra memory and performance overhead.

Conclusion

Prototype based inheritance is the way to go if you care about memory usage and performance. If you are planning to use the Closure Compiler you will also see greater code size reduction using this pattern.

Update

As some people pointed out method dispatch is slightly slower using the classic inheritance pattern because we have to walk the prototype chain to find the method. I’m also posting my tests and results for reference:

You might need to reduce the number of runs to get this to wrok in IE. The only surprising thing here is that the classical pattern is faster in Firefox nightlies.

  • http://dialect.ca/ Alex Dunae

    Thanks for this clear and concise summary.

    I’ve read countless articles on JS patterns and very few say *why* a certain class pattern should be used, only that the different options are a matter of personal preference. Obviously, they’re not.

  • http://blog.bolinfest.com Michael Bolin

    Hi Erik, thanks for the pointer and for running the experiment across various browsers. As for declaring a list of keys on the prototype, I did not mean to imply that there would no longer be a constructor function or that goog.inherits() would no longer be used — I just meant that some number of bytes could be saved if all the method declarations were done at once rather than restating Foo.prototype.methodName each time. The compiler helps with this, but it is not as compact as declaring all of the methods on a single object literal, which is Foo.prototype.

    And more importantly, thanks for creating Closure with Dan Pupius!

  • http://www.twitter.com/jdalton John-David Dalton

    @Erik keep in mind Opera does not support `__proto__` either.

    Another way to have inheritance is to do something like

    // avoid executing the Phone constructor
    function SubClass() { }
    SubClass.prototype = Phone.prototype;
    // hook up
    SmartPhone.prototype = new SubClass;
    // correct reference (optional)
    SmartPhone.prototype.constructor = SmartPhone;
    // extend prototype
    SmartPhone.prototype.sendEmail = …;

  • http://erik.eae.net Erik Arvidsson

    John-David: This is what goog.inherits does.

    goog.inherits = function(childCtor, parentCtor) {
      /** @constructor */
      function tempCtor() {};
      tempCtor.prototype = parentCtor.prototype;
      childCtor.superClass_ = parentCtor.prototype;
      childCtor.prototype = new tempCtor();
      childCtor.prototype.constructor = childCtor;
    };
    

    http://code.google.com/p/closure-library/source/browse/trunk/closure/goog/base.js#1203

  • http://www.ilinsky.com Sergey Ilinsky

    Common guys, it should not have taken 15 years to figure this out!

  • http://www.grauw.nl/ Laurens Holst

    I don’t get the private local var argument, you were already wrapping your statements in a function were you not? So what additional benefit would it then have to do this in the constructor?

    new function() {
    function extend(cBase) {
    var cPrototype = new Function;
    cPrototype.prototype = cBase.prototype;
    return new cPrototype;
    }
    var SubClass = function() {
    this.property = ‘abc’;
    }
    SubClass.prototype = extend(AnotherClass);
    SubClass.prototype.method1 = function() {
    return ‘xyz’;
    }
    // expose SubClass
    window.SubClass = SubClass;
    }

  • peter

    “an instance of the class you are inheriting from.”

    There are no “classes” in javascript. Objects.

  • http://dubroy.com/blog Patrick Dubroy

    Hi Erik,

    Do you have a reference for the “100 times slower” claim? I didn’t see anything in Michael’s articles. A quick test in Firefox 3.5 and Chrome 3.0 shows method dispatch on a functionally-created object to be twice as fast in Firefox, and about the same in Chrome. That is without using the Closure Compiler though. Are you referring only to methods that are inlined by the compiler?

  • http://erik.eae.net Erik Arvidsson

    Sergey: I’m not sure what that is a reference to? I assume you are referring to me and Michael Bolin but the whole point of this article is to inform people that the functional pattern, which is gaining foothold is the wrong way to go. I know people like you get it but there are a lot of people with less experience than you.

    Laurens: Take a look at how phoneNumber is encapsulated by the closure for getPhoneNumber. If there are other vars in the constructor these are visible inside the method bodies but not outside the constructor. So if someone has a reference to a Phone the only way to get the phoneNumber is to call the public method getPhoneNumber. In the classical pattern phoneNumber is assigned to this.phoneNumber_ which allows external access to what is supposed to be internal data. Does that make sense?

    Peter: Duh! That is why there are quotes around them. Actual there are classes in ES, but there is no way for a user to create them. Array, String etc are classes in the spec term.

    Patrick: This is at creation time. Method dispatch should be slightly faster using the functional pattern since there is no need to walk up the prototype chain. I only have the test in my dropbox atm. I’ll move it to the web server later: https://dl.dropbox.com/u/182043/inheritance-perf.html

  • http://dubroy.com/blog Patrick Dubroy

    Ok, that makes more sense. Sorry, not sure why I thought you were referring to method dispatch.

    But…in my testing, I only see it to be about 5 times slower in Chrome, definitely far from 100 times slower. This is creating 5 million objects like in your example.

    Interestingly, on Firefox, method dispatches are twice as fast on the functionally-created object (as you pointed out, because it doesn’t have to walk the prototype chain). Given that most objects would likely have methods called on them many times over the object’s lifetime, that might eliminate the speed advantages of the classical creation.

  • Pingback: mixed's me2DAY()

  • http://www.baconbutty.com Julian Turner

    Here is another approach (not original I know):-

    var phone = (function(){

    var id = 0;
    var numbers = [];

    function phone(number)
    {
    this.id = id++;
    numbers[this.id] = number;
    }

    phone.prototype.getNumber = function() {
    return numbers[this.id];
    };

    return phone;
    })();

  • http://www.baconbutty.com Julian Turner

    My above approach has one glaring error – “this.id” is public and so can be changed.

    Perhaps:-

    var phone = (function(){

    var id_count = 0;
    var numbers = [];

    function phone(number)
    {
    var id = id_count++;
    this.id = function(){return id;};
    numbers[id] = number;
    }

    phone.prototype.getNumber = function() {
    return numbers[this.id()];
    };

    return phone;
    })();

  • Pingback: Inheritance Antipattern « DesignerLinks()

  • Pingback: Lukas Mairl » Javascript()

  • Mike

    Your example/tests may not be fair. changing:

    var N = 1e5;
    var d0 = new Date;
    for (var i = 0; i < N; i++) {
    new Classic(i);
    }
    var d1 = new Date;
    for (var i = 0; i < N; i++) {
    Functional(i);
    }

    in your example to:

    var N = 1e5;
    var d0 = new Date;
    for (var i = 0; i < N; i++) {
    new Classic(i);
    }
    var d1 = new Date;
    for (var i = 0; i < N; i++) {
    new Functional(i);
    }

    greatly reduces the performance drop (from 30:1 to 4:1 in my tests on FF and Chrome). The classical pattern is still admittedly faster though.

  • http://www.dasa.cc Daniel

    I prefer prototypal based inheritance myself and is one of the reasons i created js.js (prototype.js was taken ..)

    It’s in the public domain, http://js.dasa.cc

  • laelli

    I prefer prototypal based inheritance myself and is one of the reasons i created js.js (prototype.js was taken ..)

    It’s in the public domain, http://js.dasa.cc

  • Pingback: JavaScript, example of closure functions « Andrey Vystavkin Blog()

  • http://js-bits.blogspot.com/ Juan Mendes

    I think closure based inheritance is great: truly private variables, doesn’t try to imitate JAVA. However, about 10 years ago, when I started writing OO JS, I noticed that methods is a lot more memory intensive so I stopped using it.

    Another reason is that I constantly find myself monkey patching libraries. If they had been written with closure inheritance, I would have to change their source files.

    I wrote an article talking about what makes for ‘correct’ inheritance in JS http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html