Using setInterval() / setTimeout() with function prototyping.

Author: Steven Neiland
Published:

Warning: This blog entry was written two or more years ago. Therefore, it may contain broken links, out-dated or misleading content, or information that is just plain wrong. Please read on with caution.

The last few weeks I have actively been trying to learn javascript as opposed to just hacking and hoping. So today I decided to refactor a simple set of related functions in an existing app into a class just to tidy up the code and get a handle on creating classes in javascript.

Everything was going swimmingly until I came to the function that used "setTimeout()" .

Before Refactoring

The idea of this function is that it is called on a window resize and uses the setTimeout() function to wait for half a second to determine if the resizing has been finished before executing the desired event, in this case a function named hide.

var hideTimer;

function hide() {
      // some code to hide an element
}

function waitHide() {
      clearTimeout(hideTimer);
      hideTimer = setTimeout(hide,500);
}

window.onresize = function(){
      waitHide();
}

After Refactoring

So I refactored the code and I ended up with this. Looks pretty simple right, and yet is doesn't work.

function hideTimer() {
      this.timer;
}

hideTimer.prototype.hide() {
      // some code to hide an element
}

hideTimer.prototype.waitHide() {
      clearTimeout(this.timer);
      this.timer = setTimeout(this.hide,500);
}

// Now create the timer instance
var testTimer = new hideTimer();
            
window.onresize = function(){
      testTimer.waitHide();
}

Problem: Error Function Not Defined

When I tried to run this code I encountered was this error message in firebug.

this.hide is not a function

The cause of this error turns out to be that the setInterval and setTimeout functions will take the scope to the window object. And as the hide function is wrapped inside the hideTimer object it is now effectively hidden from their view.

Solution: Closures

To fix this error we modify the setInterval/setTimeout function call using closures to pass the reference to the wrapped function.

hideTimer.prototype.waitHide() {
      clearTimeout(this.timer);
      this.timer = setTimeout(function(){this.hide();},500);
}

However this still does not fix the problem, we still get an error when we run the code. The second part of the problem is that we need to bind the hide() function call to this particular instance of the class.

To do this we create a self reference to this particular instance which we pass in in place of this. It sounds and looks redundant but it works.

hideTimer.prototype.waitHide() {
      //Create a self reference to this instance
      var self = this;

      clearTimeout(this.timer);
      
      //Call the setTimout() function but
      //this time pass in self.hide() within the closure.
      this.timer = setTimeout(function(){self.hide();},500);
}

Alternative Solution: Bind

There is a specification for newer browsers to use the bind method. I have not yet used this and I don't know what the browser support for it is like. However from what I understand this is how you would implement it.

hideTimer.prototype.waitHide() {
      clearTimeout(this.timer);
      this.timer = setTimeout( this.hide.bind(this), 500 );
}

Conclusion

I am only now really getting into really understanding javascript, but I still have to say that there are some very odd quirks to it.

Reader Comments

Nathalia Morgana's Gravatar
Nathalia Morgana
Wednesday, June 27, 2018 at 12:04:10 PM Coordinated Universal Time

Hi Steven, I just wanted to say thanks for sharing this great information. You have really saved my life with this one!! Greetings, Nathalia

  • Please keep comments on-topic.
  • Please do not post unrelated questions or large chunks of code.
  • Please do not engage in flaming/abusive behaviour.
  • Comments that contain advertisments or appear to be created for the purpose of link building, will not be published.

Archives Blog Listing