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.

What Do You Think?

Reader Comments

Post a Comment

Comment Etiquette:

  • 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 or appear to be advertisments, will not be published.
  • Comments that appear to be created for the purpose of linkbuilding to commercial sites will be removed.

We are all adults here so play nice.

*
*



Archives Blog Listing

Tag Listing

Learn CF In A Week

Treehouse

 
Fork me on GitHub