Posts tagged with 'prototype'

JavaScript for C# programmers: prototypes and privacy

Continuing my series about learning JavaScript when you're a C# programmer, using Firebug in Firebox as our testing ground.

In this episode, overriding, privacy, and class models.

Last time we saw how to create inheritance from JavaScript's constructors and prototypes, the so-called prototypal inheritance. In our example, we ended up with this:

var Point = function(x, y) {
    this.x = x;
    this.y = y;
    return this;
};
Point.prototype.move = function(x, y) {
    this.x += x;
    this.y += y;
};

This code snippet shows a couple of things I'd like to reinforce. First of all, because move is defined on the prototype for Point, it is visible to all objects we create from that constructor. If you like, since the prototype is the template for Point objects, all Point objects will have a move function. Second, the x and y fields are not shared between Point objects, but nevertheless all Point objects will have their own copies of these fields.

The concept of a class as we know it in C# is essentially split between the constructor and the prototype. If some variable (including a function) for an object is defined in the constructor, all objects created from it will have their own copy of that variable. If some variable for an object is declared on the prototype, all objects created using it will share the one copy from the prototype.

Overriding fields

But, note, however, there is a gotcha with that last sentence: it is only true when you read from the object. Let's investigate using my overworked Point example. First I'll declare a new field for the prototype called color, and I'll set it to "Red":

Point.prototype.color = "Red";

Now let's create a couple of points:

var first = new Point(1, 3);
var second = new Point(4, 2);
console.log(first.color);  // outputs Red
console.log(second.color); // outputs Red

When I read the value of first.color, JavaScript will first go to the object and see if it has a property called color. It does not. The interpreter then goes to the object's prototype object to see if it has a property called color (remember how it does this: the object first has a hidden field called constructor that points to Point, and this has the field called prototype, which is the prototype of the original object). It does, so the value of color, "Red", is returned. The same exact process happens when I call second.color. All is good; it makes sense.

What happens if I now set first.color to "Blue". What does second.color return now?

first.color = "Blue";
console.log(second.color);

There's two possible answers, "Red" or "Blue", and it hinges on what happens when first.color is set. Pat yourself on the back if you said "Red" and here's why. The chaining to the prototype only happens on a read operation. If you are writing a value, you will be modifying the object itself. So, since there is no property called color in the first object, JavaScript will create one and set it to "Blue". The common prototype.color property is not changed at all. Hence, when you read second.color, you get the chaining to the prototype operation, and "Red" gets returned.

You are, in effect, overriding a field from the object's prototype. The same thing happens when you set a function with the same name as a function in the prototype: you will override the prototype's function.

Constructing objects with private fields

In playing around with this Point example over the past few articles, I've gone from an object that had private fields but that didn't use a constructor/prototype, to an object that's lost its privacy but does have this notion of classical inheritance. Can we get the privacy back?

Remember that privacy comes from closure. Which is the only function we have that can supply privacy? The constructor. Here's a version that implements x and y as private variables:

var Point = function(x, y) {
    this.getX = function() { return x; };
    this.getY = function() { return y; };
    this.setX = function(value) { x = value; };
    this.setY = function(value) { y = value; };
    return this;
};
Point.prototype.move = function(x, y) {
    this.setx(this.getX() + x);
    this.sety(this.getY() + y);
};

Oh wow, it's suddenly a lot more complicated. The first thing to realize is that x and y are parameters to the constructor function, so they are automatically local variables and therefore private. Even more restrictive, since they are local to the constructor, they can't be seen outside the constructor, in particular by the common properties and methods of the prototype. So, the prototype's move method can't reference x and y (at least not without getting an undefined error). We have to therefore write some functions that are public and that can reference the private variables. Those functions by necessity must be defined in the constructor. And so I defined a set of getters and setters.

Note that these getter and setter functions are defined in each object, and not on the prototype. This means we're duplicating the code, but there's no way round it. It also means they can't participate in inheritance: they're defined on individual objects.

Notice also that the getters and setters are public. We are declaring them on the newly created object, and so the move method can make use of them. Douglas Crockford (the inventor of private properties in JavaScript) calls these kinds of functions privileged. A privileged function is a public method on an object that can get at the private data of the object.

Defining descendants

We've now gone into some depth about how to "do" classes by defining a constructor and by defining properties and methods on the constructor's prototype. We can define, in essence, a template for stamping out a whole set of similar objects and we know how to override properties and methods in our newly created objects. But what about further inheritance, building up a class model?

Suppose, now that we have a Point "class", we need a descendant, a ColoredPoint class, which knows its color. How is that done? We obviously need a new constructor, but that doesn't define the inheritance pattern, it's the prototype of that constructor that does. (We'll go back here to our non-privatized version of the Point "class" to avoid the noisy getters and setters.)

var ColoredPoint = function(x, y, color) {
    this.x = x;
    this.y = y;
    this.color = color;
    return this;
};
ColoredPoint.prototype = new Point(0, 0);

Notice that I've thrown away the automatic prototype object that's created with the constructor and replaced it with a fresh new Point object. I'm not particularly bothered about what values I pass when constructing this Point object, I won't be using them.

var coloredPoint = new ColoredPoint(1, 3, "Red");
coloredPoint.move(2, 2);

console.log("Point = (" +
        coloredPoint.x + "," +
        coloredPoint.y + "," +
        coloredPoint.color + ")");

Here I'm constructing a new ColoredPoint object and then I call move on it. What happens here? First, the coloredPoint object has no method called move. So JavaScript goes to the prototype object. The prototype object doesn't have a move method either. So JavaScript goes to its prototype, finally, which does have a move method. Notice how the process continues down the prototype chain, and that at the end, the function is called on the original object (which defines the value of this). The output therefore is Point = (3,5,Red) which is what we wanted and expected.

Next time, we'll throw all that away. We don't need this lookalike classical class model. Let's embrace objects!

Album cover for Zenyatta Mondatta Now playing:
Police - Voices Inside My Head
(from Zenyatta Mondatta)


JavaScript for C# programmers: prototypes, the basics

Another post in the the series that discusses JavaScript for those more familiar with C#. In this episode, the first of a couple on the topic, we look at prototypes and prototypal inheritance.

Despite the fact that the keyword class is reserved, there are no classes in JavaScript as you'd understand them from C#. And, yet, it is an object-oriented programming language: there are objects, after all. It's all made even more confusing since JavaScript has a new keyword. How does it new up an object instance, if there are no classes?

In short, instead of using classes as a template from which you can create (instantiate) objects, in JavaScript you use other objects. These objects are known as prototypes, and JavaScript uses what's known as prototypal inheritance, rather than class inheritance. The biggest problem that people have with OOP in JavaScript is that they start off from a class-based model and try and fit that model to JavaScript. Due to the flexibility of JavaScript you can get part of the way there, but it all feels a little contrived.

So, in this series, I want you to forget all about class-based OOP and start over.

Back to basics

We've already seen how to create an object by using the object literal syntax:

var point = { x: 0, y: 0 };

However, the problem with this is that the object is a one-off. What if we needed a whole bunch of point objects? They would all look the same, that is have X and Y coordinates, and possibly have methods like move() that would translate the point in some direction on the plane, or rotate() to rotate the point a certain angle around another point, and so on. That is, we need some kind of template that defines the basic data and behavior and then use that template to stamp out point objects. In C# this is what a class does, but how's this done in JavaScript?

Let's take a look. The first thing we need to do is to write a special function known as a constructor. This will construct (that is initialize) a new object.

var Point = function(x, y) {
    this.x = x;
    this.y = y;
    return this;
};

But where is the this variable coming from? In fact, what does this mean anyway?

Digression on this

In C#, this is easy: it's a reference to the current object. Since the object is an instance of a class and the method is a member of that class, when the method is called we can say with certainty which object this refers to, and what members it has and so on so forth.

With JavaScript it's not so easy. Or rather it's just as easy: this is a reference to the object the function was called on.

Here's a point object with a move method.

var point = {
    x: 0,
    y: 0,
    move: function(x, y) {
        this.x += x;
        this.y += y;
    }
};

As you can see, it's declared using an object literal. There's two fields, x and y, and the move method translates the coordinates by the displacement values passed in. It works as you'd expect from a C# viewpoint: because move is declared within point, it must always refer to that object.

point.move(1, 2);
console.log("Point = (" + point.x + "," + point.y + ")");

And the output is Point = (1,2). So here the this variable is identical to the point variable.

Now check this out:

var point3d = { x: 0, y: 0, z: 0 };
point3d.move = point.move;

point3d.move(1, 2);
console.log("Point3D = (" + point3d.x + "," + point3d.y + "," + point3d.z + ")");

Here we're defining a brand new object called point3d, with three coordinates. We set its move method equal to point's move method. (Remember, functions are objects, they are not glued forevermore to a particular definition like they are with classes in C#.) We then call point3d.move(). I think you will have worked out by now that this call will not have changed point but instead will have acted on point3d. Since the function move will have been called on point3d, the this variable will be referring to point3d. The output is Point3d = (1,2,0).

Now you're comfortable with that, check out this next bit of code.

var spacetime = { x: 0, y: 0, z: 0, t: 0 };

point.move.call(spacetime, 1, 2);
console.log("spacetime = (" + spacetime.x + "," + spacetime.y + "," + spacetime.z + "," + spacetime.t + ")");

This is downright weird, so let us take it step by step. We define a new object called spacetime. We don't define a method on it called move. Instead we call the point.move method on it and pass in the usual parameters. The call method is a method that's defined on all function objects (yes, since functions are objects they can have properties and methods on them just like any other object — this is going to be important in a moment), that takes an extra initial parameter in addition to the function's usual parameters. This initial parameter is an object on which the function gets called. This object therefore become the this variable inside the function for that call.

So the output is spacetime = (1,2,0,0).

Now, you've reread that a couple of times, all you need to remember that this refers to the object the function was called on. In particular, if you have a function inside another function (and you're already aware of this is how scope works), then the nested function's this may not be the same as the outer function's this. If you like, the scope for this is the function itself and that's it. this is always a local variable. There's no following the scope chain to try and resolve it.

By the way, if you can't "see" the object at the function's call site, it's going to be the global object, window.

Back to constructors

Looking back at our Point constructor, you can see that it refers to this. What is the value of this here? Well, if the function is called in a normal fashion:

var point = Point(1, 2);

we are going to be clobbering the global object. Why? Firstly, the object that the Point function is called on is not specified, so it is taken to be the global object, window. So, inside this call to Point, this refers to window. We'll add two new fields, x and y, and set them, and then we'll return this (which is window, remember). We then set point to this return value. Although point has the required coordinates and so looks like a point object, it's actually window, and window will have been altered. Nasty.

Instead we want to call Point, not as a normal function, but as a constructor. Enter the new keyword.

var point = new Point(1, 2);

This does what you'd expect: a new empty object is created by JavaScript and then Point is called on it. The this variable now refers to the new empty object and the statements in the function will create the new coordinate fields.

Constructors are ordinary functions

The above argument should have drilled something into you: constructors are ordinary functions, but it's the way they're called with the new keyword that makes them special. This is insane, to put it mildly. If you miss off the new keyword, you're going to be clobbering the global object and you may not even notice straight away. That's why there's a convention in JavaScript to name constructors with an initial capital letter: it's a hint to the reader that this particular function must only be called with new. Unfortunately, there's no keyword to mark a function as a constructor, nor is there some compiler/interpreter option to flag misuses for us.

Even better, there's no need to have the return statement in a constructor as I have in the Point constructor above. If there is no such statement, JavaScript will return this for you. This is yet another difference between constructors and functions:  if you don't return anything from an ordinary function, undefined is returned for you.

Inheritance

If we wanted to add the move method to our constructor, we may be tempted to do this:

var Point = function(x, y) {
    this.x = x;
    this.y = y;
    this.move = function(x, y) {
        this.x += x;
        this.y += y;
    };
    return this;
};

This would work — we'd get point objects with a move method — but it contains an inefficiency. We are in effect declaring a move method for every single point object we create with the constructor, which is enormously wasteful of memory (remember the function is not compiled but interpreted every time it is called, so we are in effect copying the same source code over and over again).

We'd prefer to have the method shared, that is, declared on the template for the point objects. So far, we don't have a template, per se, just a special function that knows how to construct point objects. Enter the prototype object.

The prototype object is the template we need. It is shared amongst all objects created from it, so if there is a method declared on the prototype object it will be visible to all such objects. But where is this prototype object declared, and how can we access it?

Every function object has a property called prototype. Normally it's an empty object and is usually ignored, but it gains a special significance for constructors. A constructor's prototype is the template from which the new keyword creates the new object before calling the constructor. In my discussion above, I glossed over this and said that the new keyword would create a new empty object. Not quite; instead it creates a new object that looks like the prototype.

Let's investigate.

var Point = function(x, y) {
    this.x = x;
    this.y = y;
    return this;
};
Point.prototype.move = function(x, y) {
    this.x += x;
    this.y += y;
};

What we have here is our original Point constructor definition, and then a statement that creates a property called move on the Point.prototype object. This method does the usual translation thing. We didn't need to declare prototype, since JavaScript creates one automatically for every single function. Now let's call it:

var point = new Point(1, 2);
console.log("Point = (" + point.x + "," + point.y + ")");
point.move(3, 4);
console.log("Point = (" + point.x + "," + point.y + ")");

Here we're creating a new point object and logging its value. We then call the move method on point. Unfortunately, point does not have a move method. On discovering that, JavaScript will then check the prototype for the method.

How does it find the prototype? Luckily for us, the new keyword has set up a hidden property for us in the new object called constructor that references the constructor function that was used to create the object; in our case, Point. So, a new object gets an extra property called constructor that points to the constructor function, and as we've seen the constructor function has a property called prototype.

So, if the method is not found in the object, JavaScript will go take a look at the prototype object to see it it has the method, instead. If so, it calls it. If it hasn't, JavaScript will check to see if the prototype object was constructed and go find it's prototype object to see if it has such a method. And so on, up the prototype chain.

Yes, you've guessed it: this is JavaScript's inheritance. Constructed objects inherit their behavior from their prototypes. Even better, given the description of how a method is called on an object, we can see that if I declare a move method on a newly created point object, it will get called in preference to the prototype object's. In fact, it hides the prototype's version. That's usually known as polymorphism and we're overriding a method.

Welcome to prototypal inheritance and polymorphism, all without a class in sight.

Oh, by the way, remember the call method above that we used to set an explicit this variable on calling a function? It's a method that's defined on all functions; or, translating into what we now know, it's a method that's defined on a function's prototype. The constructor for a function object is Function.

We'll continue with this topic next time.

Album cover for Living in Fear Now playing:
Power Station - Taxman
(from Living in Fear)



Search

About Me

I'm Julian M Bucknall, the M because it's my middle initial and because I and the other Julian Bucknall (the movie guy) would like to differentiate ourselves.

I'm a programmer by trade, an actor by ambition, and an algorithms guy by osmosis. I write articles for PCPlus in my spare time, not that there's much of that.

Julian M Bucknall Apart from that, an ex-pat Brit, atheist, microbrew enthusiast, Pet Shop Boys fanboy, slide rule and HP calculator collector, amateur photographer, Altoids muncher.

DevExpress

I'm Chief Technology Officer at Developer Express, a software company that writes some great controls and tools for .NET and Delphi. I'm responsible for the technology oversight and vision of the company.

Validation

Validate markup as HTML5 (beta)     Validate CSS

Bottom swirl

Archives

February 2012 (4)
SMTWTFS
« Jan  
1234
567891011
12131415161718
19202122232425
26272829

Like this Archive Calendar widget? Download it here.

Social networking

Google ads

The OUT Campaign

The OUT Campaign

My Tweets

Bottom swirl