5 ms·
The Illusion of Class
- deleted 14y ago[deleted]
- quarterto 14y agoDon't use Point3d.prototype = new Point(); if the constructor has side effects. Instead, function fn(){}; fn.prototype = Point.prototype; Point3d.prototype = new fn; does what you want.
- ryankinal 14y agoThat is an excellent point. I mean, ideally the constructor doesn't have side effects, but this is a good defense against those that do.
- ef4 14y agoEven 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.
- masklinn 14y agoAlternatively, if you're only supporting modern-ish browsers, Point3d.prototype = Object.create(Point.prototype); which does the same thing but does not require multiple statements (and allows adding property definitions as the second argument)
- camus 14y agoand some sell javascript as simple and well designed...
- ryankinal 14y agoSimple, sure. Well-designed? Nah. And keep in mind that this is a "classical" system tacked on top of a prototypal system. Not exactly elegant.
- dclowd9901 14y agoI don't think I've ever heard even the staunchest JavaScript writers refer to it as "well-designed".
- greggman 14y agovs? every language has worts
- baudehlo 14y agoOr if you're using Node, it's just: util.inherits(Point3d, Point);
- deleted 14y ago[deleted]
- dclowd9901 14y agoThis is a surprise to me; how do you instance the reference, then, so it isn't changed? I thought "new" did just that.
- ryankinal 14y agoI'm not sure it's exactly a problem. This will happen no matter which OO pattern you're using. It's just something you need to be aware of.
- the_gipsy 14y agoThis 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.
- deleted 14y ago[deleted]
- arethuza 14y agoWhat languages pass "objects" by value?
- PommeDeTerre 14y agoC++ is one.
- arethuza 14y agoGood point - but in practise, don't people usually pass references or pointers? [I have no idea - its been 17+ years since I last did much C++]
- thwarted 14y agoPHP4, the Object Oriented Language That Wasn't.
- msluyter 14y agoQuestion: 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.)
- ryankinal 14y agoYes it should! Good catch. (This has been updated)
- dclowd9901 14y agoWow, 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.
- jiggy2011 14y agoWhat is a "classically trained programmer"?
- ryankinal 14y agoA programmer trained in classical (as opposed to prototypal) languages. Languages like C++, Java, and PHP are classical. JavaScript and Self are prototypal.
- 2mur 14y agoI generally write my constructor functions so I can easily forget 'new': function Point(x, y){ if (!(this instanceof Point)) { return new Point(x, y); } this.x = x; this.y = y; } then you can just call: var point = Point(x, y); HT to issacs (node, npm) who I picked that up from.
- ryankinal 14y agoGood workaround! I like it.
- denysonique 14y agoFor a Class based approach -- CoffeeScript
- curtis 14y agoWhenever I find myself needing to roll my own class-based system in JavaScript I use this function: function subclass(constructor, superConstructor) { function surrogateConstructor() { } surrogateConstructor.prototype = superConstructor.prototype; var prototypeObject = new surrogateConstructor(); prototypeObject.constructor = constructor; constructor.prototype = prototypeObject; } Then you can say things like: subclass(DerivedConstructor, BaseConstructor); There's a full write-up of this approach at http://www.golimojo.com/etc/js-subclass.html http://www.golimojo.com/etc/js-subclass.html.
- epidemian 14y agoThis 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%20Base 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).
- fasteddie31003 14y agoThe JavaScript prototype pattern is the most poorly designed aspect of the JavaScript language. Cross-browser prototype compatibility is a total headache too. 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 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.
- ryankinal 14y agoI disagree. I think the prototype pattern is quite well designed. It's just not well-supported across browsers. The Pseudo-Classical/Constructor pattern is the one that's broken.
- bjhoops1 14y agoCan't help but picture GOB Bluth: "Illuuuusions, Michael!" Great article though! This is a constant source of confusion for anyone not intimately familiar with JavaScript.