The this problem
Article Index
The this problem
Solution

JavaScript has a wonderful approach to objects but it can sometimes go wrong. See if you can work out the reason for the problem in this Programmer Puzzle.

Background

JavaScript has a really interesting approach to objects and it works great most of the time. However if you come from another language background, or if you don't study how it works in enough detail, then you can find that treating it in a "classical" style might produce strange results.

A great deal of the burden of implemented objects is carried by the this operator which looks a lot like the this or me operator that you find in other object-oriented languages such as C# C++ and so on... but it isn't quite the same.

The reason is that JavaScript doesn't make use of classes, i.e. it isn't a class-based object-oriented language. In JavaScript objects are fundamentally created as literals which is fine as long as you only want a singleton object. For example:

myObject={myVariable:0,myStriing:"Hello"};

but how do you get another instance of myObject?

To allow programmers to create multiple instances  JavaScript has the constructor mechanism which is aimed at making it easy for a function to create object instances.

For example:

function MyObject(){
this.myVariable=0;
 this.myString="Hello";
}

And to make use of the constructor you write

myObject1=new MyObject();
myObject2=new MyObject();

The key point here is that the MyObject constructor generates two object litterals when called with new - one referenced by myObject1 and the other by myObject1. This works because of the use of this. When used in a constructor function this is set to reference the object literal being constructed. In other words the constructor above is equivalent to:

function MyObject(){
var obj={};
 obj.myVariable=0;
 obj.myString="Hello";
 return obj;
}

and to use this function to construct instances you don't need to remember to use new:

myObject1=MyObject();
myObject2=MyObject();

This is more or less all there is to the basic JavaScript implementation of objects - but there is one small extra that we need to consider.

The this operator is also used within methods to refer to instance variables. For example:


function MyObjectConstructor(message){
this.message=message;
 this.show=function(){
  alert(this.message);
};
}

Now when you create an instance

var myObject1=new MyObjectConstructor(
                     "Object variable1");

and call the instance's show method it accesses the instance variable message and displays the correct string.

That is

myObject1.show();

displays "Object variable1".

This might look like just another use of this but in fact it is quite different from the first use in this.message - as we will see.


Banner

Puzzle

As with all our puzzles the details of how this problem came about has been simplified as much as possible so that you can see the mechanism of what is going on.

In an effort to create a fully object oriented system the programmer introduced a new object with methods the made heavy use of instance variables - represented by:

function MyObjectConstructor(message){
this.message=message;
  this.show=function(){
  alert(this.message);
};
}

This worked perfectly, as you would expect and, for example

var myObject1=new MyObjectConstructor(
                    "Object variable1");
myObject1.show();
var myObject2=new MyObjectConstructor(
                    "Object variable2");
myObject2.show();

each displayed their own string message.

So far so simple. Next another object was created which accepted a reference to a function which it then called to get a job done. To make this simpler we can just use a varible to reference the function:

show=function(){
alert("test message");
};
var methodpointer=show;
methodpointer();

which works perfectly. This sort of statement occurs when ever you set an event handler for example or a callback function but hidden inside some complex code or object. Essentially the idea is to keep a reference to a function which can then be used to call the function at a later date.

Next the show function was refactored into an object, as shown earlier and the function reference code became:

function MyObjectConstructor(message){
this.message=message;
 this.show=function(){
  alert(this.message);
};
}
var methodpointer=myObject1.show;
methodpointer();

Unfortuntely this doesn't work and the alert simply displays "undefined".

What is going on?

Turn to the next page when you are ready to find out.

 

<ASIN:0596805527>

<ASIN:0470684143>

<ASIN:0137054890>

<ASIN:0596517742>

 

Banner