The this problem
Article Index
The this problem
Solution

 

Solution

The answer to the problem should be obvious as long as you are secure in your understanding of exactly how JavaScript objects work. The whole problem is due to the fact that there are two distinct ways that this is used within a constructor.

First let's look at the constructor again:

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

The first use of this is immediate, i.e.  it is evaluated within the constructor, and when the constructor exists the this reference isn't used again. The second use of this is deferred as it is used within a function definition.That is within any instance the show function actually reads alert(this.message) and so what this means depends on what it is set to i.e. the context of the method call. You can check this assertion using

alert(myObject1.show);

when the functions code will be displayed and you will see this within the instructions.

You can think of this as using the this value at the time the constructor is executed or using the this value at the time the method is executed.

Normally when you call a method as in

myObject1.show();

this is set to the context of the call i.e. the object that the call is made on - in this case this=myObject1 and so when the code this.message in show() executes it assesses myObject1.message.

What this all means is that the within the instances method references to the instances variables are not fully resolved even though the method is stored within the instance. This is a little odd from a pure object oriented point of view and it would be simpler if the constructor replace instance variable references with full worked out references. That is rather than store this.message within the method's code it would be better if it stored myObject.message i.e. if it evaluated the this at the time the function was constructed.

You should now be perfectly clear why

var methodpointer=myObject1.show;
methodpointer();

doesn't work. The problem is that when methodpointer calls myObject1.show this isn't set to myObject but to the global object or to what ever object methodpointer belongs to. In this case you get an undefined error because there is no message variable defined at the global level.

 

Banner

Pattern

How to avoid this one is a difficult question.

The problem arises because this used in methods within the constructor function are not evaluated. A perfect fix would be to find a way to evaluate this at the time the constructor was run and embed it in funcation definitions as a constant - this doesn't seem to be possible although with JavaScript you can never tell.

The standard way of providing context to methods so that they work even then this is incorrectly set it so save a copy of this at the time of construction.

For example:

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

Notice that this is stored in a local variable self and it is self that is used within methods whereever this would have been use. Now when you try

var methodpointer=myObject1.show;
methodpointer();

it calls myObject1.show because the context of the method call is being provided by self which was set when the constructor was called and not by this at the time the method was called.

Notice that this solution is slightly more sophisticated than you might give it credit for. Why, for example, is self defined as a local variable? Also how can the method access self when it is local to the constructor which finished running some time ago? (Recall local variables are destroyed when a function ends.) The answer is that show has access to self because a closure is formed preserving all of the constructors local variables when it terminates.

The fact that a closure is used to store the value of this at the time the constructor ran is the problem with the method. The object created by the constructor can be extended in ways that do not benefit from the closure and this means that the self variable isn't accessible from all of the objects methods. More of this in another puzzle.

 

Banner

More Puzzles

C#
Programmer Puzzle - Class and struct

This C# puzzle shouldn't be difficult as long as you are secure in your understanding of class and structs. See if you can spot the danger as soon as you read it.


Sharpen Your Coding Skills
Sharpen your Coding Skills - Elevator Puzzle

Introducing Melvin and Bugsy, characters who figure in a series of challlenges from Joe Celko. Sharpen your coding skills with puzzles that will both amuse and torment you.


Sharpen Your Coding Skills
The Best Sub-Array Problem

At first glance this puzzle seems trivial, all you have to do is find a sub-array, in an array of numbers,  that sums to the largest value. It sounds almost too easy to need a solution, let alone [ ... ]


Other Articles

<ASIN:059680279X>

<ASIN:0470526912>

<ASIN:1590597273>

<ASIN:0596806752>