30

I have a simple javascript class.

One method of this class sets up a timer using setInterval function. The method that I want to call every time the event fires is defined inside the same class.

The question is, how can I pass this method as a parameter to the setInterval function?

One attempt was setInterval('this.showLoading(), 100). But doesn't work. This method access class properties, so I need the 'this' reference.

This is the sample code:

    function LoadingPicture(Id)
    {
        this.imgArray = null;
        this.currentImg = 0;
        this.elementId = Id;
        this.loadingTimer = null;
    }


   LoadingPicture.prototype.showLoading = function()
    {
        if(this.currentImg == imgArray.length)
            currentImg = 0;

        document.getElementById(this.elementId).src = imgArray[this.currentImg++].src;
    }


    LoadingPicture.prototype.StartLoading = function()
    {
        document.getElementById(this.elementId).style.visibility = "visible";
        loadingTimer = setInterval("showLoading()", 100);
    }
0

3 Answers 3

44

setInterval can take a function directly, not just a string. https://developer.mozilla.org/en/DOM/window.setInterval

i.e.

loadingTimer = setInterval(showLoading, 100);

But, for optimal browser compatibility, you should use a closure with an explicit reference:

 var t = this;
 loadingTimer = setInterval(function(){t.showLoading();}, 100);
3
  • 1
    The latter approach being the more generally applicable. +1
    – xtofl
    Commented Jan 4, 2010 at 20:25
  • Yeah, depends... I think the former works in AS3, but I can't remember if it does cross-browser in JS. The latter is usually the safest. Commented Jan 4, 2010 at 20:27
  • 1
    I tend to call the variable that. As in: var that = this; :)
    – AO_
    Commented Sep 5, 2013 at 15:57
28
loadingTimer = setInterval("this.showLoading()", 100);

Firstly, don't use string arguments to setInterval/Timeout. It's dodgy in the same way as using eval, and may similarly fail with CSP security restrictions in the future. So instead:

loadingTimer = setInterval(this.showLoading, 100);

However, as you say, this will lose the owner reference so the called function won't see the right this. In the future (the newly-defined ECMAScript Fifth Edition), you will be able to bind the function to its owner with function.bind:

loadingTimer = setInterval(this.showLoading.bind(this), 100);

and if you implement function.bind yourself for browsers that don't yet have it (see the bottom of this answer), you can use this syntax today.

Otherwise, you will need to use an explicit closure, as in the example Computer Linguist just posted.

6

All the answers above are acceptable. I just wanted to add that the binding of this can also be solved by using an arrow function. For example, these are all equivalent to each other. However, the lexical scope is maintained when using arrow functions:

 // Arrow function - my preferred method
 loadingTimer = setInterval(() => this.showLoading(), 100);

 // .bind method
 loadingTimer = setInterval(this.showLoading.bind(this), 100);

 // Other method
 var t = this;
 loadingTimer = setInterval(function(){t.showLoading();}, 100);

Hope this helps :D

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.