

Understanding Prototypical Inheritance in JavaScript  - laktek
http://laktek.com/2011/02/02/understanding-prototypical-inheritance-in-javascript/

======
demallien
Am I alone in really not liking the use of the .prototype property in
Javascript?

For starters, it doesn't play well with native classes, so if you're trying to
bind native objects to Javascript, it's going to create problems. For example,
when using .prototype, the constructor creates a pure Javascript object - for
JavascriptCore at least, pure Javascript objects don't have the possibility to
be linked to a native object, with JSObjectSetPrivate() returning an error.

Secondly, it just generates all sorts of problems with handling of member
variables - every instance of a subclass objects links to just one copy of the
parent class, which means that all of the subclass instances share state -
this is generally not what is wanted in subclassing.

Crockford suggests using prototyping in a more free-form manner, as follows:

    
    
      function MySubclass()
      {
          var that = new MyParentClass();
          that.newMemberFunction = function()
          {
          }
          return that;
      }
    

which corrects both of the problems that I mentioned above. Personally I use
this style a lot in Ruby as well as JavaScript, which shows that it is more
portable than .prototype as well.

~~~
jashkenas
Just because Crockford suggests it, doesn't make it a good idea.

Manufacturing objects with a factory function, avoiding the "prototypal" part
of JavaScript, is slow, wastes memory, and prevents you from using
"instanceof" to compare objects.

The point of a prototype is to share common functions and properties that
don't change among instances. With "MySubclass", you manufacture a new copy of
every function in the class, each time you create a new instance, with all of
the closure-related overhead that entails.

Last time I benchmarked it, comparing a simple class with ten methods, in both
prototypal style, and factory style, in Chrome:

Empty page, no objects: 0.9 MB

1 mil constructor objects: Brief pause, 32.4 MB

1 mil factory objects: About a minute pause, 368.1 MB

That said, if you know you're only going to have a dozen instances of the
object on the page, then it hardly matters.

~~~
praptak
_"Just because Crockford suggests it, doesn't make it a good idea."_

On top of that Crockford does not actually state that closure-based objects
should be preferred to prototypal inheritance. See:
<http://javascript.crockford.com/prototypal.html>

~~~
jashkenas
To repeat myself: Just because Crockford suggests it, doesn't make it a good
idea.

Here's a set of benchmarks for creating a new instance, using the pattern you
just linked to (called "Crockford Create" within):

[http://jsperf.com/object-create-vs-crockford-vs-jorge-vs-
con...](http://jsperf.com/object-create-vs-crockford-vs-jorge-vs-
constructor/9)

In Safari, it's about 5X slower than using a regular constructor function. In
Chrome, it's about 20X slower.

In JS, just using prototypes as Eich intended is the way to go.

~~~
praptak
_"To repeat myself: Just because Crockford suggests it, doesn't make it a good
idea."_

I did not suggest anything like this. My point was that Crockford pretty much
enumerates every sensible way to do inheritance in JS, with the conclusion
quite similar to yours - Crockford suggests (in fact: describes) many things,
so don't draw too much from this.

Btw, he suggests the regular constructor too:
<http://javascript.crockford.com/inheritance.html>

------
praptak
If you set a function's 'prototype' property to a new object, it's a good
practice to set the object's 'constructor' property back to the function, so

    
    
        Triangle.prototype = new Shape(3, 3);
    

should be followed by:

    
    
        Triangle.prototype.constructor = Triangle

~~~
regularfry
Why is this?

~~~
praptak
That's the default on any function you create in JS. This prints 'true':

    
    
        var f = function() {};
        document.write(f.prototype.constructor == f);
    

This alone isn't perhaps a very important reason to keep this invariant, but
it makes some basic reflection possible. This is (among other things) useful
for debugging. It's just sometimes useful to be able to check the problematic
object's "class", or at least something as close to class as you can get in a
classless language.

