How Javascript Prototypal Inheritance Really works
blog.vjeux.com
blog.vjeux.com
Firstly, __proto__ is nonstandard, and deprecated. If you write JavaScript that uses it, it won't run in all JS runtimes.
Object.create is similarly not available everywhere. It's not available in Firefox < 4, IE < 9, or any version of Opera. Crockford's version of Object.create is not compatible with the native Object.create -- and if you patch it in, you may end up breaking libraries that expect the real thing.
But let's say you had it all sorted out, and you had a sane plan for using the native Object.create, and falling back to Crockford's implementation where unavailable ... it's still not a great pattern:
http://jsperf.com/object-create-vs-crockford-vs-jorge-vs-con...
Running that again today, I see that in Chrome, instantiating objects via Object.create -- either Crockford's or native -- is over 95% slower than using a regular constructor function. We're talking about just creating basic objects here, low-level stuff: how fast you can do it is pretty important if you're aiming for high-performance JavaScript.
The prototype property, constructor functions, and "new" are the way that JavaScript objects work, and the way that engines are tuned to optimize JS code. Avoid learning to use them at your own peril.
[1]: https://developer.mozilla.org/en/Differential_inheritance_in...
I've had this debate with folks many times before, and literally every time it comes up, they're unable to find an example of using prototypal inheritance in a style that wouldn't also be considered classical.
If you think that writing:
var point = Object.create(Point);
... is somehow magically prototypal, while writing: var point = new Point;
... is unnaturally classical, I'll argue that you're missing the, ahem, point.They're two different ways of writing the exact same pattern. And, if we're being honest with ourselves, the "Point" object in that code should rightly be called a "class": it's the abstract object that defines the shape of all points. Of course, in JavaScript, we also tend to call it the "constructor function" (which it is, technically), and sometimes, the "prototype" (because it serves in that role).
Prototypal inheritance makes a difference if one instance inherits field values (other than functions) from another instance. But this does not seem to be very common.
I believe one of the original use cases for prototypal inheritance were to save memory by letting GUI controls share common properties. Eg. if you had 10 buttons on the screen which all had the same color, same dimensions etc. With class based inheritance each instance would have their own copy of all properties, even if they have the same values in each instance.
I don't think that kind of optimization is relevant in modern JavaScript.
What is no mistake is the refreshing change of view you get when you start embracing objects and prototypal inheritance. See for example the traits library[1, 2].
[3]: Is a cursory introduction to Self, with another points example :)
[4] Contains an example of my own (heavily inspired by Self and Io). I have stitched together various internet sources to come up with `clone', an operator assisting in differential inheritance.
[1]: http://traitsjs.org/
[2]: http://code.google.com/p/es-lab/source/browse/trunk/src/trai...
A factory is very different from a keyword baked into the language. The new keyword suggests that the underlying language is doing the construction, and all of the details about the object being created are encoded in its blueprint, "Point."
I consider a factory and a keyword to be two very different patterns regardless of whether you want to call them class-based or prototype-based.
Aside from the simplicity argument, I didn't see anything in Markus's presentation that showed an advantage of prototypes. His point example is cloning a point and then immediately replacing all of the state, so there's nothing there that classes couldn't do (in less code).
Your gist (especially the color point) is an example of using prototypes in a way that's hard with classes. Fortunately, adding classes to JS won't hurt that at all. You could just as easily do:
class Point {
constructor(x, y) {
public x = x;
public y = y;
}
add(other) {
return new Point(this.x + other.x, this.y + other.y);
}
}
let p1 = new Point(0, 0);
let p2 = p1.clone({
color: '#green',
toString: function() {
return this.color + ': ' + uber(this).toString();
},
})
In other words, adding classes to JS won't take away anything already there. It just gets a really common pattern and makes it much less verbose. The idea is to pave the common path of class-like inheritance, but not to build a fence around it to keep you in.When I was learning js (ie getting over the jquery hump) I could have used this because the new operator is so damn unintuitive. This is a good article for learning how prototypes really work in js.
The objective of the article is to explain how prototypal inheritance works and how it relates to the new operator. The use of real prototypal inheritance was added at the end, just to note that it was possible.
Guys, don't spread ignorance.
Implementation details aren't essential, therefore a "bad practice" in this respect is just an ignorance.
Once again: the difference between classical and prototype-based (delegation-based in this case) inheritance is _ideological_.
In first case (classical) we have systematized (classified) code reuse, in the later (prototypal) -- unclassified (or "chaotic") code reuse, i.e. "I reuse/inherit the behavior and state from that object from which I want".
There are no other differences. The implementation details are derived stuff. Moreover, the same implementation can provide both, classical and prototypal _approaches_ of a code reuse (good examples: Python - prototype-based language, CoffeeScript, JavaScript, etc). Because a "class" isn't a syntactic construct, inst' some specific implementation. It's the _ability to classify_ objects. And this ability can be achieved in different systems regardless an implementation.
So if you need a classical code reuse with predefined "shapes" of your objects - you build a classical system reusing the code form linear ("tower") chain of inheritance. If instead you need just reuse a small functionality regardless of the classical hierarchy -- you use prototypal inheritance, that is delegation based traits/mixins/prototypes. And JS has both of them -- classes (without sugar) and prototypes -- and they both can be used when needed, there is no "bad practice" in this case.
Regarding classes and their kinds (that's why Python is also prototype-based langauge with "classes as sugar", the same as in Coffee, the same as is planed for ECMAScript): https://gist.github.com/977034
You may find additional info on common theory of OOP and in particular in ECMAScript with all details in "ECMA-262-3 in detail. Chapter 7.1 / 7.2".
Dmitry.
Personally I like the prototypal style, and would like it to be optimised.
There's a glimmer of hope though. In Firefox 4.0.1 Object.create is almost as fast as new Constructor. If other implementations caught up in this respect what are your feelings on new vs. Object.create?
new Point(20, 100);
The problem in JS isn't the "new" keyword, it's how awkward and brittle prototypes are to create. You have to know to first define a constructor function (read "class object"), and then attach prototypal properties to it one at a time. If you intend to use the prototype chain for inheritance, you have to be even more careful, and bend over backwards to configure the prototype chain correctly, which requires the creation of a temporary intermediate function.See later in this thread: http://news.ycombinator.com/item?id=2595128 ... nasty stuff. Verbose, fragile, and confusing.
This is why the ECMAScript committee is hard at work on proposals like these:
http://wiki.ecmascript.org/doku.php?id=strawman:classes
http://wiki.ecmascript.org/doku.php?id=strawman:classes_as_i...
http://wiki.ecmascript.org/doku.php?id=strawman:classes_as_s...
http://wiki.ecmascript.org/doku.php?id=strawman:classes_with...
http://wiki.ecmascript.org/doku.php?id=strawman:classes_with...
That said, I wouldn't base my coding decisions on those kinds of micro benchmarks. They say nothing about the impact on actual javascript applications. Using new instead of Object.create may prove completely irrelevant in an application where you are constantly updating the DOM or are doing lots of network calls.
I'm an old NewtonScript coder -- I wrote a JVM for the Newton, for example. NewtonScript is a fairly pure proto-OO language, and it was great to work in. I was thinking of getting into JavaScript, but after reading this article I am shocked, SHOCKED, at how bad JS appears to be.
Class-style OO has really one major advantage: speed. You can do object slot lookups in O(1). Otherwise it's mostly disadvantages: it's very wasteful of memory, it's not dynamic, it mates poorly with functional programming styles, and its unnecessarily complex.
Let me get this straight. JavaScript is proto underneath (and thus is slow), but strives so hard to feel like a Class-style OO that it has deprecated developer access to ITS OWN PROTO OPERATOR. Thus it loses most of the advantages of proto languages except memory consumption, and still has all of their disadvantages.
And this nightmarish condition was all done in order to shield the coming-from-C++ developer from having to "learn" the trivial concept of proto-style OO? And ten years later it's STILL the case?
There are a couple of fine points: In JS, using regular constructors, object slot lookups still tend to be O(1)-ish -- engines like V8 optimize the "hidden class" of the object by assuming that all instances share the same rough shape, with guard checks if you start to change your properties dynamically later.
Also, regular constructors in JS are much more memory-efficient than the popular alternative "module pattern", which looks like this:
var makePoint = function() {
var x, y;
return {
getX: function(){ ... },
getY: function(){ ... },
distance: function(){ ... }
};
};
var point = makePoint();
Because functions in JS are mutable objects with their own identity, guess what happens each time you create a point? You've just duplicated every function that the point uses as a method, including their closure. It gobbles up memory to the point where you can't make more than a few thousand instances of any object, no matter how small.With "new Point", in JS, there's only ever one copy of the point's functions in use -- living on Point.prototype -- and all this is avoided.
Finally, class-based OO can be fully dynamic these days, it just depends on how you want to implement it: see Ruby, where any object can have a "metaclass" with its own complement of methods.
My understanding is that Python does these things because it's in the SAME bag as JavaScript: it's actually a proto language in implementation down deep, but with a class-based syntax, thus inheriting the disadvantages of both and the advantages of neither. There's some dynamicism bubbling up from the object implementation but it's a far cry from the elegance of a real proto language. I do not know why Guido chose to do this awful thing, but he is at least to be excused given the age of the language. JavaScript has no such excuse.
If you think of classes in Python as a feature build on top of prototypal inheritance, then it has certainly proved a very useful feature.
http://www.ecma-international.org/publications/files/ECMA-ST...
Bear in mind that it's still a work in progress. Look for "populus.object", especially create(), is_a() and call_super(). There is still something called $new (not new because some picky parsers don't like it) but it's just the chaining of create() (a wrapper around Object.create()) and init().
Proto = {
cloneConstructor: new Function,
clone: function()
{
Proto.cloneConstructor.prototype = this;
return new Proto.cloneConstructor;
}
}
var Point = Proto.clone();
Point.x = 0;
Point.y = 0;
Point.print = function()
{
console.log(this.x, this.y);
}
var p = Point.clone();
p.x = 10;
p.y = 20;
p.print(); //10 20https://github.com/joyent/node/blob/master/lib/util.js#L410
This correctly sets this.constructor on instances of any subclass.
Instead, use a function like this:
var inherits = function(child, parent) {
var ctor = function(){};
ctor.prototype = parent.prototype;
child.prototype = new ctor;
ctor.prototype.constructor = child;
};In my test case crockford's create is seemingly faster for this, but I'm sure I'm missing something. Someone mind educating me here?
After calling this function, the child constructor's prototype is an object with no own properties, which itself has the parent's prototype, so references to properties of the parent's prototype will resolve and objects created using the child constructor will return true for "instanceof parent".
The other step usually involved, which isn't shown here, is to put `Parent.call(this)` (with any necessary arguments) in the child constructor.
No it doesn't.