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.

20 thoughts on “Inheritance Antipattern

  1. Alex Dunae Nov 10, 2009 09:50

    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.

  2. Michael Bolin Nov 10, 2009 14:50

    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!

  3. John-David Dalton Nov 10, 2009 21:21

    @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 = …;

  4. Erik Arvidsson Nov 10, 2009 21:41

    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

  5. Sergey Ilinsky Nov 11, 2009 01:01

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

  6. Laurens Holst Nov 11, 2009 03:19

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

  7. peter Nov 11, 2009 07:32

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

    There are no “classes” in javascript. Objects.

  8. Patrick Dubroy Nov 11, 2009 08:12

    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?

  9. Erik Arvidsson Nov 11, 2009 09:48

    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

  10. Patrick Dubroy Nov 11, 2009 11:29

    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.

  11. Pingback: mixed's me2DAY

  12. Julian Turner Dec 8, 2009 03:09

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

  13. Julian Turner Feb 24, 2010 09:13

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

  14. Pingback: Inheritance Antipattern « DesignerLinks

  15. Pingback: Lukas Mairl » Javascript

  16. Mike Aug 13, 2010 13:44

    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.

  17. Daniel Sep 13, 2010 08:40

    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

  18. laelli Nov 6, 2010 20:29

    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

  19. Pingback: JavaScript, example of closure functions « Andrey Vystavkin Blog

  20. Juan Mendes May 18, 2011 12:50

    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

Comments are closed.