Tel +49 (30) 814504070

Detlef Hüttemann
04.07.2006 14:55 Uhr

JavaScript closures and the mysterious this

Tags:

Closures is a concept of programming languages, which is easy to use (and often used), but it (and its consequences) is rarely understood.

Closures simply means:

If you can see a variable declared outside, you can use it.

That sounds trivial for global variables:

var name = 'enzo';
function myName () {  alert( name + ' erhardo'); }
myName(); // will alert 'enzo erhardo';

The power of closures is unleashed when declaring the function inside of another function. With closures you can use the local variables of the outer function.

There is a common problem when using eventhandler or timer functions in javascript: you often have to pass object pointer to eventhandler. Especially when coding OO-style, you want to invoke instance methods instead of globals functions - precise: you want to pass the “this” pointer.

The following example binds an onclick handler to a html element which starts a interval timer:

function StopWatch ( node ) {
  this.node = node;
}
StopWatch.prototype.start = function () {
  this.started = new Date();
  this.itvid = setInterval( **timer**, 500 ) ; 
  this.node.style.backgroundColor = 'lightgreen'; 
}
StopWatch.prototype.stop = function () {
  if ( this.itvid ) clearInterval( this.itvid ) ;
}
StopWatch.prototype.update = function () {
  this.node.innerHTML = new Date() - this.started;
}
var stopwatch = new StopWatch ( document.getElementById('test') );
  • *function timer () {

stopwatch.update() ;

}**

The problem is the timer function. You want to pass the “this” pointer to it. With closures, the solution is simple. The trick is to define a local function inside of the function start. The local function can use all local variables. Unfortunalety this wont work for the this pointer, but you can copy it to a local variable self:

function StopWatch ( node ) {
  this.node = node;
}
StopWatch.prototype.start = function () {
  **var self = this;**
  this.started = new Date();
  **var timer = function () { self.update(); };**
  this.itvid = setInterval( **timer**, 500 ) ;  
}
StopWatch.prototype.stop = function () {
  if ( this.itvid ) clearInterval( this.itvid ) ;
}
StopWatch.prototype.update = function () {
  this.node.innerHTML = new Date() - this.started;
}
var stopwatch = new StopWatch ( document.getElementById('test') );

The function start can be abbreviated to

function start () {
**  var self = this;
  this.itvid = setInterval( function () { self.update(); }, 500 ) ;**  
}

This is a common used idiom when using eventhandler and timer: creating inner functions and using outer variables with closures.

If you want to see the script in action, click here. This example creates two stopwatches which can be started and stopped independently.

Bookmark and Share

Comments

Older Comments

Benedetto Cattarinich
2007/02/07 10:03

Great! I was looking for this explaination and code from a long time. I'd be glad to read other articles from the same author. Benedetto (Benny)Cattarinich Web Developer

About CosmoCode

CosmoCode is a Berlin based IT service provider with a strong emphasis on web applications. We mainly focus on Content Management Systems, Wikis and custom solutions.

Subscribe

Subscribe Like our blog? Stay up to date via RSS
Freie Stelle: Fachinformatiker Freie Stelle: Fachinformatiker