tags:

views:

121

answers:

3

I have an object defined like this:

Blah = {

   hideTimer:null,

   setTimer: function() {
    this.hideTimer = window.setTimeout(Blah.hidePopupInner, 500);
    // must be done via window due to Greasemonkey
   },

   hidePopupInner: function() {
    log("This? " + this);
   },

   hidePopupInnerPublic: function() {
     Blah.hidePopupInner();
   }
}

The problem is that the 'this' in killTimer is not set to Blah. If I change the line to say

    this.hideTimer = window.setTimeout(Blah.hidePopupInnerPublic, 500);

then the 'this' is pointing to Blah so the hideTimer can be utilized.

Making a 'public' method for each method solves the problem, but there must be an easier solution...?

Note: This is all in Greasemonkey, but I think it's a general Javascript question.

+6  A: 

To solve this, you can use anonymous function and scope reference when building timeout.

(code...)
setTimer: function() {
    var _this = this;
    this.hideTimer = window.setTimeout(function(ms){
        _this.hidePopupInner();
    }, 500);
},
(code...)

PS: Moreover, setTimeout will pass the number of milliseconds to invoked function. For example: imagine your function can receive one parameter, and do some stuff with it. But because setTimeout will pass milliseconds to your function, it can lead to unexpected errors.

nemisj
Could you clarify your PS? You mean in my code in the question it will do this?
Yar
My PS, is just my own experience with setTimeout, it will not make any problems in your case.
nemisj
Perfect, thanks for that
Yar
I kind of doubted this code, but then I tried it out :) Still not sure why the ms is in there, as it doesn't change the results...
Yar
ms is there just to show that setTimeout pass argument to the handler
nemisj
I marked this best answer, because it is. But it seems that the PS is wrong, at least on Firefox. No parameters are passed to the hidePopupInner, even if its signature is changed to allow params.
Yar
You can put alert box inside to see that, the ms is there, it is just not passed to your hidePopupInner function :)window.setTimeout(function(ms){ alert(ms); _this.hidePopupInner();}, 500);
nemisj
Okay, thanks for your responses, still digesting all of this.
Yar
+2  A: 

Basically function specified as setTimeout param is executed like callback.
Reason you're not getting Blah context is you switching to setTimeout scope (even when using Blah method).

I don't know Greasemonkey at all, however using Function methods like Bind will help you. If there is no function like bind in GM, you can alwyas write it but yourself (couple of lines of code) - can copy PrototypeJS one.
http://www.prototypejs.org/api/function/bind

It basically executes prepares your function with specifed scope:

// inside Blah
setTimeout (Blah.hidePopupInner.bind(this), 500);

Actually Tableton's solution is Bind's implementation on fly

Tomasz Durka
cool, I'll check it out, or I might even package Prototype with my script. Thanks!
Yar
+1  A: 

Though not a true solution to the scope issue, you can at least get around Blah.killTimerPublic by doing:

window.setTimeout(function(){ Blah.hidePopupInner() }, 500);
Justin Swartsel
Thanks Justin. While this works, it only works for one instance... which is how it's defined in this case anyway, so +1
Yar