5 ms·
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, __prot
by jashkenas 15y ago
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:
http://jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor/10 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.
- raganwald 15y agoI'm with Jeremy on this. Languages all have their own character and way of doing things. Cut with the grain, not against it.
- Autre 15y agoI 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 :) [1]: https://developer.mozilla.org/en/Differential_inheritance_in_JavaScript https://developer.mozilla.org/en/Differential_inheritance_in...
- jashkenas 15y agoI 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).
- olavk 15y agoVery 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.
- Autre 15y agoWell, 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. [1]: http://traitsjs.org/ http://traitsjs.org/ [2]: http://code.google.com/p/es-lab/source/browse/trunk/src/traits/examples.js http://code.google.com/p/es-lab/source/browse/trunk/src/trai... [3]: http://www.cs.aau.dk/~bt/DAT5E08/MarkusKrogh1.pdf http://www.cs.aau.dk/~bt/DAT5E08/MarkusKrogh1.pdf [4]: https://gist.github.com/997910 https://gist.github.com/997910
- rimantas 15y agoThe conclusion of the article is also quite weird, as if article offers some radically different mechanism, while in reality is just a wrapping.
- olavk 15y agoYeah, 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.
- Androsynth 15y agoHe 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.
- vjeux 15y agoThanks 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.
- DmitrySoshnikov 15y ago> 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 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.
- justincormack 15y agoYou 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.
- sjs 15y agoThat 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?
- jashkenas 15y agoMy 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. See later in this thread: http://news.ycombinator.com/item?id=2595128 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 http://wiki.ecmascript.org/doku.php?id=strawman:classes_as_inheritance_sugar http://wiki.ecmascript.org/doku.php?id=strawman:classes_as_i... http://wiki.ecmascript.org/doku.php?id=strawman:classes_as_sugar http://wiki.ecmascript.org/doku.php?id=strawman:classes_as_s... http://wiki.ecmascript.org/doku.php?id=strawman:classes_with_trait_composition http://wiki.ecmascript.org/doku.php?id=strawman:classes_with... http://wiki.ecmascript.org/doku.php?id=strawman:classes_without_trait_composition http://wiki.ecmascript.org/doku.php?id=strawman:classes_with...
- ootachi 15y agoNote 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.
- joske2 15y agoAccording 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.
- shawndumas 15y agohttps://twitter.com/sstephenson/status/74534160705916928 https://twitter.com/sstephenson/status/74534160705916928
- SeanLuke 15y ago??? 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?
- jashkenas 15y agoYep, you've got that all about right. 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.
- olavk 15y ago