admin管理员组

文章数量:1323323

I recently tried to optimize some code for an often created value object. (A three dimensional vector, fwiw)

One thing I tried was to convert the constructor function from an anonymous method factory pattern to a normal JavaScript constructor.

This led to a severe performance penalty which surprised me, since the use of 'new' and normal constructors was much remended in my last question on the subject of JavaScript constructor/factory patterns.

It could well be that my test is too simplistic, or just plain wrong, or a result of recent performance optimizations made in chrome's JavaScript engine, or all of the above. In any case, I'd really like to know why my 'optimizations' led to performance drop - and - most important: Is there any obvious problem with my jsperf testrun?

I recently tried to optimize some code for an often created value object. (A three dimensional vector, fwiw)

One thing I tried was to convert the constructor function from an anonymous method factory pattern to a normal JavaScript constructor.

This led to a severe performance penalty which surprised me, since the use of 'new' and normal constructors was much remended in my last question on the subject of JavaScript constructor/factory patterns.

It could well be that my test is too simplistic, or just plain wrong, or a result of recent performance optimizations made in chrome's JavaScript engine, or all of the above. In any case, I'd really like to know why my 'optimizations' led to performance drop - and - most important: Is there any obvious problem with my jsperf testrun?

Share edited May 23, 2017 at 11:45 CommunityBot 11 silver badge asked Jan 2, 2013 at 16:17 ZazZaz 3,0342 gold badges24 silver badges29 bronze badges 8
  • crockford is fastest for me by ~50% – Darren Kopp Commented Jan 2, 2013 at 16:26
  • 2 @Zaz: 2 things...1) Does crockford claim his method is faster? I thought it was just that it avoided globals and was therefore "safer". 2) Are you sure what you are showing there is what Crockford remends? I was thinking more along the lines of the last example on this page...javascript.crockford./prototypal.html...if I'm wrong (probably) could you link me to where you're getting this from as I'm currently doing a reread of "The Good Parts" – heisenberg Commented Jan 2, 2013 at 16:45
  • you're paring 2 things that don't do the same thing, neither of which is Crockford's object constructor. – Evan Davis Commented Jan 2, 2013 at 17:34
  • @Mathletics: There would be no reason to pare two identical bits of code. What behavioral or performance differences are there between the two techniques presented, beyond the construction performance difference already noted? – Scott Sauyet Commented Jan 2, 2013 at 18:37
  • 1 @ScottSauyet the question suggests he's testing Crockford's constructor; paring setting prototype directly vs using the new keyword. Two methods of creating an object, but certainly not "identical bits of code." The entire question is about construction performance, but the tests provided aren't representative of the question that I think the OP thinks he's asking. – Evan Davis Commented Jan 2, 2013 at 18:42
 |  Show 3 more ments

2 Answers 2

Reset to default 4

The major differences between your tests are:

  • {} is way faster than new Object, which suggests that new is simply slower than using {}. (The same is true of [] and new Array.)

  • Your tests produce different results: the result of your make factory function isn't a Make object. The constructed Make has a prototype, shared by all Make objects. Your result of your factory function is just a bare Object, and has a single prototype in its prototype chain (Object.prototype), whereas the Make constructed object has two (Make.prototype, followed by Object.prototype).

    I made a fork of your test, with a factory function that actually returns a Make object (instead a simple Object), using the non-standard __proto__ property, and it is much slower than a using a constructor. IE does not support __proto__, but the results from Firefox and Chrome look pretty definitive.

One of the things that a constructor function optimizes for is shared properties, usually methods. If a number of objects use the same functions as methods, or share other named properties, then one assignment to the prototype will share a single instance of the property among all objects created from the constructor, reducing memory overhead, and will not need to repeat the assignment of each such property for every object created, reducing construction time overhead.

Since your sample does not include any such properties, you're not going to see such benefits. But if your production code does not include shared properties for your constructed object, there might well be no reason to switch to a constructor.

So, if, for example you had code like this:

function make(p) {
    return {
        parm: p,
        addTwo: function() {return this.parm + 2;},
        double: function() {return this.parm * 2;},
        square: function() {return this.parm * this.parm;}
    };
};

it will probably run more slowly than this:

function Make(p) {
    this.parm = p;
}
Make.prototype.addTwo = function() {return this.parm + 2;};
Make.prototype.double = function() {return this.parm * 2;}
Make.prototype.square = function() {return this.parm * this.parm;}

It will also take a lot more memory if you create many instances.

本文标签: performanceIs crockford39s JavaScript constructor pattern really supposed to be fasterStack Overflow