I'm sorry to be difficult about this, but ... Like many other Crockford-inspired takes on the subject, vjeux's article is massively bad advice.
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:
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.
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.
I think you are conflating static typing with class-based OO. Python for example is class-based but still fully dynamic. You can mutate classes at runtime, and even replace the class of an instance at runtime, OTOH Python cannot do the slot lookup optimization you speak of, due to its dynamical nature. Python shows that class-based inheritance is very useful (and easy to use) in a dynamic language.
I believe you may have picked the one language which inadvertently illustrates my point.
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.
I guess you could argue that Python is a prototype language deep down because it performs property lookups at runtime by following a chain of objects. (Those objects just happen to be classes.) But by that definition, other dynamic OO languages like Perl or Ruby is also prototype languages.
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.
Exactly, Python is a "prototype-based" language with first-class classes as sugar; similar to Coffee. I gave a link below where kinds of classes are described.
He doesn't appear to be advocating using this as a practical coding style. It is simply a way of showing people whats really going on with new and the prototype chain by writing it out in javascript.
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.
I don't see how Object.create goes against the grain of the lang. On the contrary, `new' was bolt on to make js look like classical oo languages. I have found, in toy and exploratory projects at least, that using variations on Object.create [1] is a nice, strong pattern, that really gets the best out of js. It certainly feels more natural than class based oo. Though, take it with a grain of salt, since I'm unable for now to provide an example backing my thesis :)
I would love to see an example backing your thesis, if you don't mind digging one up.
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).
Very few examples of prototypal inheritance shows it beeing practically different from class based inheritance. If all (non-function) instance fields are assigned new values - like the Point example in the article - it is basically the same.
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.
Well, I have to argue that it's not the same pattern. I think the problem
is that you still like to believe that js has classes, which it doesn't: js
has got objects only. That it also has constructor is an (admitted?)
historical mistake. Just think of all the weird crap that goes on to make
`new func()' work and produce a new object.
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.
Traits aren't incompatible with classes at all. In fact, Tom van Cutsem, the author of traits.js worked on the class proposal that's going into Harmony.
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.
Object.create(...) is a factory pattern. "Object" is suddenly a factory for making anything, you just supply the blueprint in the form of "Point." So to know what will happen, I need to look at Object and at Point. One strength of this pattern is when I want to handle cross-cutting concerns in the factory. For example, I can modify all objects created with aspects if I use a factory to create them. Or I could have the factory decide whether it is creating Plain Old Javascript Objects or whether each object is backed by persistent storage a'la ActiveRecord.
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.
According to that benchmark native Object.create is faster than constructor functions on Firefox 4.
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.
Note that the slowness of Object.create in V8 (it forces objects into hashtable mode) is the reason that Chrome did so poorly on the JSLint benchmark. Given the popularity of that benchmark, I suspect that Chrome will get around to optimizing Object.create sooner rather than later.
Yeah, I don't get why it is suddenly real prototypal inheritance just because it uses a wrapper function which hides the constructor. The resulting instance have exactly the same inheritance semantics.
Thanks for the comment. I have added big red (orange ...) boxes to let the user know that it is considered bad practice.
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.
> Thanks for the comment. I have added big red (orange ...) boxes to let the user know that it is considered bad practice
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".
You could also view this as a missing optimisation opportunity on Chrome. Firefox and Safari manage ok. Chrome has some excellent optimisations for new but I dont think it is the case that these could never be applied to native object.create.
Personally I like the prototypal style, and would like it to be optimised.
That is eye opening, thanks. I can't believe how much faster new is.
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?
My feelings are that "new" is really what you want. If you're thinking, "I want to make a new point at 20, 100", you probably want to write:
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.
I guess everyone is used to language standards written in a very academic style so they ignore them, but if you really want to know how Javascript works, the ECMAScript specification is clearly written in semi-layman terms and includes a very good explanation of that picture they include at the bottom of the article.
It took me a while to get it, especially since the new keyword makes matters really confusing. But after reading about the language Self, I am really using prototypal inheritance, and no more of the "new" business for me.
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().
The note should be much bigger. And __proto__ really isn't "supported" anywhere: it's an implementation detail. It's been deprecated in Mozilla, and Opera used not to have it (as recently as 2009, though there is now an __proto__ property on all objects).
> Let’s take a basic figure of an object with which we will operate in the following descriptions. A prototype of an object is referenced by the internal [[Prototype]] property. However, in figures we will use __<internal-property>__ notation, and in particular for the prototype object: __proto__ (that’s moreover, is a real, but non-standard, implementation in some engines, e.g. SpiderMonkey).
It uses __proto__ but makes quite clear that the property is just an implementation detail of the graphs.
You don't want to have to actually instantiate an object using the parent constructor in order to get an object with the parent's prototype chain attached for inheritance purposes, as you'd either have to code all constructors which will be inherited from defensively, or pass in dummy arguments to satisfy the constructor when inheriting, which could preclude using a function with no knowledge of the parent constructor such as this one.
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.
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.