...

View Full Version : Object classes and setTimeoout



VR2
07-11-2006, 01:57 PM
In the example below, why is it that when the dog takes a dump, the "this" property is accessible to all object methods, as you would expect.

But when the dog Barks, the first time though, all pointers are valid and "this" is accessible to all methods but after being called from setTimeout the loop() method loses its "this" reference, and yet the Bark method (called from loop via the function pointer) retains it.

The only difference is that the function poointer for Dump AND Loop is passed in when the dog dumps, but only the function pointer for Bark is passed in when the dog barks.

Why can I not define these function pointers in the class declaration, and have them still be valid even when called from a different thread via the setTimeout?


<html>
<head>
<title>Object Test</title>
<SCRIPT>
function Dog()
{
this.instance = 0;

this.BarkString = "Woof";
this.DumpString = "Dumping away like a dog.";
this.Bark = function(){alert("Bark has access to this.BarkString: (" + this.BarkString + "), because it was passed in as a param");};
this.Dump = function(){alert("Dump has access to this.DumpString: (" + this.DumpString + "), because it was passed in as a param");};

this.StartLoop = function(numLoops, ptrCall, ptrOptional)
{
m_Method = ptrCall;
// If they pass up the loop method, then use it, else use the default member var
if (ptrOptional)
m_LoopMethod = ptrOptional;

m_CurrLoop = 0;
m_NumLoops = numLoops;
this.Loop();
};
this.Loop = function()
{
// In this method we cannot access the "this" propery...!!!
if (m_CurrLoop == 0)
alert("First time through, we are called in the UI thread so DO have access to this.BarkString: " + this.BarkString);
else
alert("So why now can I Access: m_memberString (" + m_MemberString + ") but not this.BarkString(" + this.BarkString + ") UNLESS we passed the function in (as when we are Dumping)??");

m_Method();
if (m_CurrLoop++ < m_NumLoops)
setTimeout(m_LoopMethod, 1000);
};
var m_MemberString = "Member String";
var m_NumLoops = 0;
var m_CurrLoop = 0;
var m_LoopMethod = this.Loop;
/* Note this does not work
var m_LoopMethod = function(){this.Loop()};
*/
var m_Method = this.Bark;
}


var dog = 0;
function MakeDog()
{
dog = new Dog();
}

function Bark()
{
dog.StartLoop(5, function(){dog.Bark()});
}
function Dump()
{
// Do a dump but pass in the loop method, meaning that when it executes
dog.StartLoop(4, function(){dog.Dump()}, function(){dog.Loop()});
}
</SCRIPT>
</head>

<body onload="MakeDog()">
<span style="font-family: Arial"><strong><span style="font-size: 14pt">Why is it?<br />
</span>
<br />
Why is it </strong>that when the dog Barks, the .Loop() method loses its "this" reference (gets set to that of the page!!) but when the dog does a poo, the fact that the calling code passes a reference to the .Loop() method, the loop method
retains its "this" reference?</span><br />
<br />
<button onclick="Bark()">Start Barking (loses "this")</button>
<button onclick="Dump()">Start Dumping (retains "this")</button>&nbsp;<br />
<br />
<span style="font-family: Arial">Why do I have to pass in a reference to the function?
Why cannot the class define this internally? if it can, how do I?
</span>
</body>
</html>

Beagle
07-11-2006, 03:59 PM
"this" is a special keyword that always refers to the executing context, it is a dynamic reference and is evaluated each time it is encountered.

All other variables are static references to their defining context, and once the referrent is determined, it does not change.

This has interesting implications for object-oriented programming in JavaScript. You can read a lot more on the "this" keyword at http://www.quirksmode.org/ in his JavaScript section, or do some research on google.

To fix your problem though, your object should have a private variable that stores the defining context and that should be used in place of this when attempting to refer to public members of your object from within the object:



function Dog()
{
var self = this;
this.sound = "woof";

this.bark = function()
{
alert(self.sound);
}
}


This technique allows you to predictably access member variables from within the object in any execution context.

VR2
07-11-2006, 04:50 PM
Wow, nice idea, thanks, that might *just* work :)

I'll give it a try...

VR2
07-11-2006, 05:02 PM
That is fantastic - it *WORKS*!!!!!:thumbsup:

This is going straight into my "Best Practices" when writing javascript classes. Why have I never heard of this before? :)

As you say, the key is that this allows you to
predictably access member variables from within the object in any execution context. and thus is very useful to know indeed. Essential tip!

Many, many thanks again :)



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum