By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,851 Members | 1,095 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,851 IT Pros & Developers. It's quick & easy.

Having multiple object instances use the same variable without overriding each other.

Atli
Expert 5K+
P: 5,058
Hi everybody.

This is not so much a problem, since I have already managed to find a solution, but my solution requires the use of the eval() function, which I just hate to use.

The problem is this.
I have an object that has a function. This function needs to call itself in a setTimeout call. Using the "this" keyword from within the callback function will obviously not work, seeing as it would reference the new function rather than the object instance.

So, in an attempt to solve that, I create a reference to "this" before I create the callback function and use that inside the callback function, like so:
Expand|Select|Wrap|Line Numbers
  1. // Minimized the code to get to the point
  2. function Updater(pTargetElement, pMaxValue)
  3. {
  4.     this.update = function(pCurrent)
  5.     {
  6.         self = this;
  7.         window.setTimeout(function(){
  8.             self.update(pCurrent);
  9.         }, 50);
  10.     }
  11. }
  12.  
And this works... almost.

The object is meant to manipulate an element, taking an initial value and counting up until the max value is reached, displaying the current value in the given target element.
And this does exactly that... if I have only one instance of the object running at a time.

Once a second instance is in play, the two will be fighting over the "self" variable, which is apparently created in a scope that both instances use.

As a result, if a first instance sets the "self" value to itself and fires of the setTimeout, a second instance may be called before the timeout is reached, altering the "self" variable, which is then reflected in the timeout calls from both objects.

This effectively doubles the effect on the second instance, while the first instance is left unchanged.

And this is my problem. How do I create the "self" variable in a scope that is unique to each object instance? So when the second instance is called, it will not alter the variable created by the first instance.

But, like I said, I managed to find a solution by using the eval() function.

My thinking was that the main problem is the second instance re-using the same variable. So I created a "dynamic" variable by creating a random number and turning that into a variable by running it through the eval function.
Like so:
Expand|Select|Wrap|Line Numbers
  1. function Updater(pTargetElement, pMaxValue)
  2. {
  3.     this.update = function(pCurrent)
  4.     {
  5.         rand = Math.floor(Math.random() * 10000);
  6.         eval("self_" + rand + " = this;\
  7.               window.setTimeout(function(){\
  8.               self_" + rand + ".update(" + pCurrent + ");\
  9.               }, 50);");
  10.     }
  11. }
  12.  
This is obviously flawed. Even tho it is a pretty safe method, there is always a chance that the random numbers collide causing a problem, not to mention that this will create a bunch of random variables that are left lying around.

This can be used, and my use of it will be limited so the potential of problems is minimal, but there just has to be a better way.

This is the full code I am using to test this, just in case:
Expand|Select|Wrap|Line Numbers
  1. function Updater(pTargetElement, pMaxValue){
  2.     this.targetElement = pTargetElement;
  3.     this.maxValue = pMaxValue;
  4.  
  5.     this.update = function(pCurrent){
  6.         if (pCurrent >= this.maxValue) {
  7.             return;
  8.         }
  9.         ++pCurrent;
  10.         this.targetElement.innerHTML = pCurrent.toString();
  11.  
  12.         rand = Math.floor(Math.random() * 10000);
  13.         eval("self_" + rand + " = this;\
  14.               window.setTimeout(function(){\
  15.               self_" + rand + ".update(" + pCurrent + ");\
  16.               }, 50);");
  17.     }
  18. }
  19.  
  20. function bodyOnLoad(){
  21.     for (i = 1; i <= 3; i++) {
  22.         eval("window.setTimeout(function(){\
  23.               updater = new Updater(document.getElementById(\"Counter" + i.toString() + "\"), 50);\
  24.               updater.update(0);\
  25.               }, (250 * " + i.toString() + "));");
  26.     }
  27. }
  28.  
This uses three "CounterX" <div> elements as containers, each of them counting up to 50, one starting 250ms after the other.
And (shockingly) this work in all my browsers except IE.

Any input would be greatly appreciated.

Thanks,
- Atli r
Oct 11 '08 #1
Share this Question
Share on Google+
3 Replies


rnd me
Expert 100+
P: 427
you should not have to use eval at all.

you need to use "var" before defining the function, rather than evaling it as a global.

also, "self" is a reserved word, replace it with "that".
Oct 11 '08 #2

Atli
Expert 5K+
P: 5,058
Thank you for that.

I didn't realize "self" was reserved in JavaScript, but you are right, it appears to be a shortcut to "window".
Although, none of the browsers seem to have a problem with me redeclaring it.
In any case, I've change that now.

I don't really know what you mean by:
you need to use "var" before defining the function, rather than evaling it as a global.
I'm not sure what the "var" keyword has to do with defining functions. I thought it was only used with variables?

But, this had me do a little research on it, and I found out something interesting.

Until now, I thought that declaring a variable without the var keyword was equivalent to declaring it with it, with the exception that it could be explicitly deleted.

As it turns out, when I add the var keyword to the variable I previously called "self", it became unique to that instance! Which pretty much takes care of the problem for me.

Now I have this code, which works perfectly in all my browsers. (even IE!)
Expand|Select|Wrap|Line Numbers
  1. function Updater(pTargetElement, pMaxValue)
  2. {
  3.     this.targetElement = pTargetElement;
  4.     this.maxValue = pMaxValue;
  5.  
  6.     this.Start = function(pDelay)
  7.     {
  8.         var _this = this;
  9.         window.setTimeout(function(){
  10.             _this.update(0);
  11.         }, pDelay);
  12.     }
  13.  
  14.     this.update = function(pCurrent)
  15.     {
  16.         if (pCurrent >= this.maxValue) {
  17.             return;
  18.         }
  19.         ++pCurrent;
  20.         this.targetElement.innerHTML = pCurrent.toString();
  21.  
  22.         var _this = this;
  23.         window.setTimeout(function(){
  24.             _this.update(pCurrent);
  25.         }, 50);
  26.     }
  27. }
  28.  
  29. function bodyOnLoad()
  30. {
  31.     for (i = 1; i <= 3; i++) {
  32.         updater = new Updater(document.getElementById("Counter" + i.toString()), 50);
  33.         updater.Start(i * 250);
  34.     }
  35. }
  36.  
Thank you for the help. I would probably never have thought to look into that if you hadn't mentioned it :)
Oct 11 '08 #3

rnd me
Expert 100+
P: 427
Thank you for that.
Until now, I thought that declaring a variable without the var keyword was equivalent to declaring it with it, with the exception that it could be explicitly deleted.

As it turns out, when I add the var keyword to the variable I previously called "self", it became unique to that instance! Which pretty much takes care of the problem for me.

Thank you for the help. I would probably never have thought to look into that if you hadn't mentioned it :)
using var inside a function creates a local instance variable.

what i was getting at is that eval can screw with the scope, and you were clobbering a global version of the function with every eval.

using the function expression instead of eval is going to be a lot faster, simpler, and more reliable.

one tip: put 'var _this = this;' at the top of the constructor, and avoid repetition in sub functions. this could reduce memory usage slightly as well.

i probably should have been a little more specific, but i'm glad you go it working and learned a little bit.


the code in the second looks a lot nicer than the first.

cheers
Oct 11 '08 #4

Post your reply

Sign in to post your reply or Sign up for a free account.