Even side-effect free constructors can make this pattern painful. Consider the case where we're trying to maintain the invariant that all Points always have valid numbers for all their coordinates:
var Point = function(x, y)
{
if (typeof(x)!='number' || typeof(y)!='number'){
throw new Error("...");
}
this.x = x;
this.y = y;
}
Now you're forced to pick an arbitrary point when setting up the prototype, which is kinda gross.
My point is that people write constructors with the expectation that they'll only be used for constructing meaningful objects.
This has nothing to do with JavaScript, this is basics of pass-by-reference in garbage collected languages. Hint: only primitives are "copied" into functions, objects are references; {}, [] and new Foo are all objects in JavaScript.
Question: in the object tree for Point3d, it looks like there are two __proto__ attributes at the same level of nesting. Should the second belong to Point and be indented? (I'm not that experienced with javascript so I could simply be confused.)
Wow, that was super confusing. I had better reread. Otherwise, great article and examples. I had a pretty good notion of prototype, et. al., but felt like this article really escalated my intrinsic understanding.
A programmer trained in classical (as opposed to prototypal) languages. Languages like C++, Java, and PHP are classical. JavaScript and Self are prototypal.
This technique of the surrogate constructor is exactly what CoffeeScript uses under the table when using the extends operator. E.g. http://coffeescript.org/#try:class%20Derived%20extends%20Bas.... It also copies all the properties on the super constructor to the derived constructor, so you can have the "class level methods" in the derived classes too.
One of the main benefits i found of using CoffeeScript's sugar for classical inheritance is that i no longer need to stop and think "ok, so am i doing things right here?" every time i inherit from a class or call a "super" method, which was the case when writing JS. It Just Works (TM).
The JavaScript prototype pattern is the most poorly designed aspect of the JavaScript language. Cross-browser prototype compatibility is a total headache too.
36 comments
[ 3.8 ms ] story [ 65.3 ms ] threadMy point is that people write constructors with the expectation that they'll only be used for constructing meaningful objects.
I think I'll be updating the article to include your modifications. Thanks (and how should I attribute? ef4 on HN?)
And keep in mind that this is a "classical" system tacked on top of a prototypal system. Not exactly elegant.
[I have no idea - its been 17+ years since I last did much C++]
One of the main benefits i found of using CoffeeScript's sugar for classical inheritance is that i no longer need to stop and think "ok, so am i doing things right here?" every time i inherit from a class or call a "super" method, which was the case when writing JS. It Just Works (TM).
My solution: abstract away the headache. Use Underscore's extends function or take a look at how Prototype.js handles inheritance: http://prototypejs.org/learn/class-inheritance .
Both solutions are much more simple and do the same thing.
Also, if you are going into a JavaScript interview, know the stupid prototype pattern, someone always asks about it.
The Pseudo-Classical/Constructor pattern is the one that's broken.
Great article though! This is a constant source of confusion for anyone not intimately familiar with JavaScript.