Javascript: OOP Style Performance

I have been watching parts of Douglas Crockford’s talks on the history and future of Javascript. In his third talk Douglas talks about functions. If you are somewhat familiar with Javascript you know that functions are, somewhat oddly, used to create new objects. The original “intended” way (which Douglas calls the pseudo-classical way) of doing this is as follows:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.getNameAndAge = function() {
  return "Name: " + this.name + " and age: " + this.age;
};

var p = new Person("Zef Hemel", 26);
console.log(p.getNameAndAge());

What we do here is define a constructor function Person, which starts with a capital P, to indicate that it should be used in conjunction with the new operator, as demonstrated in the second last line. The second statement adds a method to the Person prototype, which in practice makes that method available to all Person objects (including ones already created). The last two statements instantiate a Person object and calls the getNameAndAge method.

Using this mechanism you can also implement inheritance. Let’s introduce a LivingBeing “super class”, which has an age property:

function LivingBeing(age) {
  this.age = age;
}

LivingBeing.prototype.getAge = function() {
  return this.age;
};

Alright, now we’ll define the Person contructor again, but assign a new instance of LivingBeing to its prototype, which will add all fields and methods available in LivingBeing to all Person objects (again, including existing ones). Then, we add an additional method to Person objects: getNameAndAge:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype = new LivingBeing();

Person.prototype.getNameAndAge = function() {
  return "Name: " + this.name + " and age: "
         + this.getAge();
};

var p = new Person("Zef Hemel", 26);
console.log(p.getNameAndAge());

For more information on how inheritance and prototypes work, read this excellent page in the Mozilla documentation.

Now, Crockford suggests that there is a nicer, cleaner and more natural way to do object-oriented programming and inheritance in Javascript, which he calls functional inheritance. The functional-inheritance style version of the above program looks as follows:

function livingBeing(age) {
  return {
    getAge: function() {
      return age;
    }
  };
}

function person(name, age) {
  var that = livingBeing(age);
  that.getNameAndAge = function() {
    return "Name: " + name + " and age: " + that.getAge();
  };
  return that;
}

var p = person("Zef Hemel", 26);
console.log(p.getNameAndAge());

Note that the invocation style of the constructors changed here too, no new keyword should be used. I agree that this is a nice style, although it makes extending existing objects with additional methods/fields hard, but one could argue this is a bad idea anyway. Although clean, it also seems more expensive to execute, because you’re basically composing an object from scratch every time — you start out with an empty object and that push in all its methods and fields — while with the pseudo-classical approach you create one prototype object with all the methods, and then simply point to that object. Theoretically calling a method would then be more expensive, because at invocation-time the prototype hierarchy has to be traversed. But maybe Javascript engines have a clever solution to all of this and in practice it doesn’t matter. I decided to investigate.

I benchmarked two things:

  1. The performance of object creation, by creating 10x 1,000,000 objects
  2. The performance of method calling on a single object, by invoking a method 10x 1,000,000 times

I did each 10 times, so that I can take an average time on each. I executed this benchmark on four browsers running on my Mac (Macbook Pro):

  • Firefox 3.5
  • Chrome 5 (dev)
  • Safari 4
  • Opera 10.50b

Disclaimer 1: The reason I executed these on these four browsers is not to compare their performance, this is not a good way to compare browser performance, but mainly to check that the results in different browsers do not diverge too much.

Disclaimer 2: What I’m testing is not representative for real programs. If one approach is going to be twice as fast as the other, this does not imply that your programs are going to be twice as fast, it means that object creation is twice as fast, or method invocation is twice as fast. Whether that matters to you depends on the amount of objects you create or methods you call.

Benchmark 1: Object creation

This benchmark creates 1,000,000 objects. First using the pseudo-classical style and then through the functional style. The code to this benchmark can be found here. The times reported are in milliseconds for 1,000,000 objects being created. As mentioned, every test is performed 10 times of which I took the average:

Update: The previous version of the benchmark script contained a major flaw that increased the execution time of the functional style considerably. This has now been adjusted in the graph. Thanks Adrian for noticing this.

This chart clearly shows that creating objects using the pseudo-classical style is cheaper in all browsers. This varies from about 35% cheaper (Chrome) up around three times as cheap (Firefox). If you create huge amounts of objects in your code, you may want to take this into consideration.

Benchmark 2: Method invocation

This benchmark creates one object and then invokes the same method on it 1,000,000 times. First using the pseudo-classical style and then through the functional style. The code to this benchmark can be found here. The results are as follows:

I would have expected that method invocation would have been cheaper in the functional style of object creation, but it turns out it’s not. The differences here are almost negligible, so I’d say that in practice it doesn’t really matter what style you choose if your application is heavy on method calls.

Still, I felt that the functional style must be cheaper especially if you use inheritance. So I adapted my benchmark script to introduce a level of inheritance (like the LivingBeing “super class”). However, method calls using the pseudo-classical style are still cheaper, although less so. Perhaps, if you use 4+ levels in your object hierarchy, the functional style method calls may start to become cheaper (although I expect creating those objects will be much more expensive).

It seems that method invocation on objects created using the functional style are roughly as expensive as using the pseudo-classical style.

Conclusion

There are two properties to take into account when deciding what object-creation style you’re going to use in your code.

  1. Which style produces clearer code? This depends on the taste of both on the developers of the code, but if you’re developing a library for others, possibly also on the expectations of your audience. Scanning through some Javascript libraries it seems the pseudo-classical approach is much more popular. Consequently, your audience is likely going to expect and be more comfortable with this approach. That’s something to take into account.
  2. Is the code CPU/memory intensive, does it create lots of objects? If so, the pseudo-classical approach is superior.
Got something to say?
  1. mweststrate says:

    Interesting results! The performance is worse than expected. I'll still give the functional a try sometimes, because typically the only objects created frequently are dom nodes.

    And i prefer the syntax of the functional approach. I have a hard time accepting that defining inheritance takes multiple statements.

  2. Zef Hemel says:

    > because typically the only objects created frequently are dom nodes.

    That's mostly true for simple AJAX scripts, but once you build more and more of your application using Javascript (like I'm doing for mobile web apps), you create more and more custom objects, so this may become an issue.

  3. Zef Hemel says:

    I was just pointed to this article, which has very similar findings: http://erik.eae.net/archives/2009/11/09/21.12.16/

  4. Bob says:

    Nice article! You're a good explainer – I had some fuzzy idea of how this worked and you pulled it all together for me in just a few words – and the benchmarks were on point. The functional style seems simpler to me and it's faster. What's not to like?

  5. Nam E. says:

    From a procedure perspective, those graphs should probably be the most favorable results for each method after N tries, because you have shown (through your sample) that the method is at least that good.

  6. Zef Hemel says:

    Thank you for the kind words, but the functional style is the slower one. By far.

  7. jwmcpeak says:

    Personally, performance should be the only consideration. As you said, clearer code is subjective to each individual. What's clear to me may be convoluted to you. Contrast that with performance, which isn't dependent upon personal preference and doesn't change.

  8. justinjohnsonorg says:

    It would be interesting to include classical-classical object construction in your benchmarks

    function Person(name, age) {
    this.name = name;
    this.age = age;

    this.getNameAndAge = function() {
    return “Name: ” + this.name + ” and age: ” + this.age;
    };
    };

    I expect that instantiation would be expensive, but method access would be similar to the pseudo-classical results.

  9. Adrian says:

    There's a bug in your benchmark: the functional inheritance constructor test calls a method as well as calling the constructor, which the classical inheritance test does not. Based on the results, this should reduce the reported times for function inheritance object creation down by at least 10%.

  10. Zef Hemel says:

    Crap, you're right. Thank you. I will fix it tomorrow.

Trackbacks for this post

  1. Emend > zef.me > the second to last line
  2. Quora

Comments are closed now.