Skip to content

Instantly share code, notes, and snippets.

@ryankinal
Created January 29, 2013 17:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ryankinal/4665907 to your computer and use it in GitHub Desktop.
Save ryankinal/4665907 to your computer and use it in GitHub Desktop.
Article on pseudo-classical pattern
<blockquote>This indirection was intended to make the language seem more familiar to classically trained programmers, but failed to do that, as we can see from the very low opinion Java programmers have of JavaScript. JavaScript's constructor pattern did not appeal to the classical crowd. It also obscured JavaScript's true prototypal nature. As a result, there are very few programmers who know how to use the language effectively.
~ Douglas Crockford, <a title="Douglas Crockford - Prototypal Inheritance" href="http://javascript.crockford.com/prototypal.html">"Prototypal Inheritance"</a></blockquote>
The indirection Mr. Crockford refers to here is the <em>Pseudo-Classical</em> <em>Pattern, </em>also known as the <em>Constructor Pattern</em>.<em> </em>This is a way of simulating classical inheritance in JavaScript - a prototypal language.<!--more-->
If it wasn't obvious from both the title of this post, and from the frankly negative quote above, this is not my favorite object-oriented pattern in JavaScript. I'll go into this in further detail as I teach the pattern, but the reasons have to do with semantics, usability, verbosity, and blatant indirection. If you don't pay too much attention to the details, the pattern is actually rather usable. But when you get into the meat of how this pattern simulates classical inheritance from a prototypal system, you see the flaws in the foundation. That said, the pattern can and has been used effectively, and there is one distinct advantage it has over other OO patterns in JS. We'll get to that later as well.
I'll be examining the pseudo-classical pattern in comparison with the basic prototypal system. If you don't know how JavaScript's prototype system works, then I suggest you read <a title="Objects and the Prototype Chain" href="http://blog.javascriptroom.com/2013/01/14/objects-and-the-prototype-chain/">Objects and the Prototype Chain</a>, and come back later.
Otherwise, let's jump right in.
<h2>The Basics</h2>
[javascript]
var Point = function(x, y)
{
this.x = x;
this.y = y;
}
Point.prototype.translate = function(x, y)
{
this.x += x;
this.y += y;
}
var point = new Point(17, 42);
point.translate(5, 6);
[/javascript]
Easy enough! But what do we end up with? Well, we end up with a new object of type <em>Point</em> with a prototype equal to <em>Point.prototype</em>. Check it out.
[javascript]
Point
x: 22
y: 48
__proto__: Object
constructor: function (x, y)
translate: function (x, y)
__proto__: Object
[/javascript]
We have a <em>Point</em> object, with <em>x</em> and <em>y</em> properties, and a prototype that contains the <em>translate</em> function. Sweet! Now for something a little more complicated.
<h2>Inheritance</h2>
Unlike a normal classical language, JavaScript has no <em>extends</em> keyword. There is no way for a constructor to directly inherit from another constructor.
Well... sort of. There's the <em>prototype </em>property that functions have. And when the function is used as a constructor (with the <em>new</em> keyword), you get a new object that has a prototype equal to the function's <em>prototype</em> property, so a new "instance" of a constructor function will inherit from that function's <em>prototype</em> property. This is <em>kind of</em> like having an <em>extends</em> keyword.
That last paragraph was probably confusing. And I apologize for that. It really stems from the poorly-chosen naming conventions involved in the pseudo-classical pattern. I'll discuss this more later, but for now, here's an example of inheritance in the pseudo-classical pattern.
[javascript]
var Point3d = function(x, y, z)
{
Point.call(this, x, y);
this.z = z;
}
Point3d.prototype = new Point();
Point3d.prototype.translate = function(x, y, z)
{
Point.prototype.translate.call(this, x, y);
this.z += z;
}
var point3d = new Point3d(19, 20, 21);
point3d.translate(4, 5, 6);
[/javascript]
There's a lot going on here.
First, we need to create our constructor for <em>Point3d</em>. Easy enough; It's a function, just like <em>Point</em> was in the previous example. We use <em>this</em> just like we did previously, but to avoid code duplication, we can use <em>Point.call</em> - changing the calling context of the <i>Point</i> function to whichever new object we create (referenced by <i>this</i>). The new object, in this way, gets <em>x</em>, <em>y</em>, and <em>z</em> properties, just like we want.<em>
</em>
Then we determine the inheritance structure by setting <em>Point3d</em><em>.prototype</em> to a new instance of the <em>Point</em> constructor. All our <em>new Point3d</em> objects will now have a prototype equal to an object with an prototype equal to <em>Point3d.prototype</em>. Did you catch that? There were a lot of different "prototype"s in there, and not all of them mean the same thing.
Lastly, we take advantage of the prototype chain, setting <em>Point3d.prototype.translate</em> to a 3d version of the <em>translate</em> function. In this function, again, we take advantage of the <em>call</em> function to avoid code duplication.<i>
</i>
That's a lot of structure, and the naming gets really confusing at this point. Maybe just looking at the structure will help. This is what our <em>new Point3d</em> object looks like:
[javascript]
Point3d
x: 23
y: 25
z: 27
__proto__: Point
translate: function (x, y, z)
x: undefined
y: undefined
__proto__: Object
constructor: function (x, y)
translate: function (x, y)
__proto__: Object
[/javascript]
I hope that clears things up a little.
<h2>Why Is This So Confusing?</h2>
Well, as mentioned at the beginning of this article, constructors were tacked on to the language at the last minute, in hopes of satisfying programmers trained in classical languages (like Java or C++). I can't imagine much thought was put into it.
This is evident in the naming conventions. Every function has a <em>prototype</em> property, which is used solely for the pseudo-classical style. But it <em>is not</em> the prototype of the function - that would be the <em>__proto__</em> property (in most JS engines). This indirection causes one really big issue, which was demonstrated above: It makes it really hard to talk about the <em>prototype property</em> versus the <em>prototype of an object.</em> The domains of the two concepts overlap, and when using the pseudo-classical pattern, they are intertwined; The use of functions as constructors depends on the <em>prototype property</em>, and affects the <em>prototype of objects.</em><em>
</em>
This is a big reason why I avoid the pseudo-classical pattern. It removes the <em>prototype</em> property from the equation, and thus reduces the cognitive load required. Ironically, if you understand how it all works, you can forget the details and might be able to take advantage of <em>new</em> as a useful abstraction.
<h2>What's Good?</h2>
As much as I dislike this pattern, there are some interesting, and possibly useful parts of it. This, of course, is up for debate, and different people will likely see these in completely different lights.
<strong>Familiarity</strong>
Many of us "grew up" with classical languages. "Desktop" or "Application" developers may be familiar with Java, C++, or Python, as might developers who studied Computer Science formally. Web developers are likely familiar with PHP or C#. All of these are classical languages, and it can be a boon to see familiar constructs, even if they don't function quite as they would in the languages we're used to.
<strong>It's Used Internally</strong>
When we want a new <em>Date</em> object, we use <em>new Date</em>. We can also do the same with <em>Array</em> if we choose (though literals are preferred). Using constructors in our own code can keep everything looking the same.<i>
</i>
<strong>Types</strong>
With the pseudo-classical pattern, we can take advantage of <em>instanceof</em> and <em>typeof</em> operators on our own objects. If you're into that kind of thing (which you probably shouldn't be - see the <em>What's Bad?</em> section, below), then <em>typeof point3d </em>will return <em>"Point3d"</em> and <i>point3d</i> instanceof <em>Point</em> will be true.<em>
</em>
<strong>The Naming Convention</strong>
This may be due to my classical education, but I really like capitalizing constructors (<em>Point3d</em>) and lowercasing instances (<em>point3d</em>). It makes naming less of a hassle.
<h2>What's Bad?</h2>
<strong>Prototype vs. Prototype</strong>
This was discussed above. The <em>prototype</em> property of a function is not the function's prototype, but it could be the prototype of a different object. 'nuf said.
<strong>Familiarity</strong>
The use of <em>new</em> might be familiar, but it's kind of familiar in that <a href="http://en.wikipedia.org/wiki/Uncanny_valley">Uncanny Valley</a> sort of way. It looks like it's classical, but it just isn't. The differences are big enough to cause issues. There is no explicit <em>extends</em>, and there are no real classes (there probably will be, but that's an issue for a different post). You have to fake it, which is why this is the <em>pseudo-classical </em>pattern.<i>
</i>
<strong>Verbosity</strong>
There's a lot of <em>x.prototype.y</em>, and even some <em>x.prototype.y.call</em>, and that's rough on the eyes.
<strong>Forgetting <em>new</em></strong>
Constructors are just functions, which means they can be called regularly, without the use of the <em>new</em> keyword. This causes a problem when using <em>thi</em><em>s</em> inside of the constructor - it will no longer reference the new object. Instead, it will reference the global object. In the browser, this means setting <em>this.x</em> will set <em>window.x</em>. If you're diligent, this won't be a problem. But it could be an interesting bug to find.
<strong>Type</strong>
In the realm of the browser, there has long been a focus on feature detection, rather than browser detection. It's considered good practice to check for a feature before using it, rather than make assumptions based on possibly falsified data - the UA string.
The same can be said of checking for type in JavaScript. When using <i>instanceof</i> and <em>typeof</em> with native objects, you'll run into issues, so it may be a poor decision to get into the habit of using those operators with your own constructs.
It's far preferable to use <a title="Duck Typing" href="http://en.wikipedia.org/wiki/Duck_typing">Duck Typing</a>, rather than rely on the type of an object. Check for properties, and if they exist, then use them. After all, if it "walks like a duck and swims like a duck and quacks like a duck", then it might as well be a duck.
But it's still not going to tell you it's a duck.
<strong>Un-needed Abstraction</strong>
The <em>new</em> keyword is an abstraction of two different steps that can be achieve quite easily using a clearer and more prototypal method. Assuming we have our structure already set up, the following pseudo-classical code:
[javascript]
var point3d = new Point3d(19, 20, 21);
[/javascript]
Is equivalent to the following code using the initializer pattern:
[javascript]
var specificPoint = Object.create(Point3d);
point3d.init(19, 20, 21);
[/javascript]
Is the abstraction really needed? I guess that's up to you.
<h2>Final Thoughts</h2>
Crockford was right. The pseudo-classical/constructor pattern is an indirection. It's confusing, and it prevents people from learning the language effectively.
Underneath, it uses the prototype chain, and it adds some interesting (possibly useful) features on top of it. But if you don't understand the prototype chain to begin with, then you're probably not going to be able to use constructors effectively.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment