Nerdworks logo "The nerd shall inherit the earth."

Nerdworks Blogorama

Nerdspeak

JavaScript closures act like implicit function state?
Technobabble
7/12/2009 3:36:27 PM

Consider this JavaScript code:

function acc( n ) {
    return function( i ) {
        return n += i;
    };
}

var fn = acc( 5 );
var n1 = fn( 1 );
var n2 = fn( 2 );

The question, of course, is what the values of n1 and n2 will be. It is perhaps evident that n1 must now equal to 6. But what about n2? Will it now contain 7 (i.e. 2 + 5) or will successive calls to fn result in the parameters being accumulated by addition with the value that was passed to acc (5)? We find by experimentation that the latter turns out to be true. n2 now equals 8, i.e., 5 + 1 + 2!

The conclusion to draw here therefore is that JavaScript function closures are essentially implicit function state. In the code snippet given above, if you treat fn as a regular object (which in fact it is), then the variable n which is part of the closure captured by the function object when it was returned from acc now acts like member state of fn. This is why multiple calls to fn causes the mutation to n to persist across those calls.

This is further corroborated by the fact that a subsequent call to acc to create another function object results in that instance getting a separate copy of the closure containing n. Here's an example:

function acc( n ) {
    return function( i ) {
        return n += i;
    };
}

var fn = acc( 5 );
var n1 = fn( 1 );
var n2 = fn( 2 );

var fn2 = acc( 10 );
var n3 = fn2( 1 );
var n4 = fn2( 2 );

Here, n3 and n4 hold 11 and 13 respectively. The function fn has no effect whatsoever on fn2 (or vice versa). This in fact, is the basis for creating the C++ equivalent of private member data in JavaScript. Imagine that you wish to create the equivalent of the .NET StringBuilder class and want to make the buffer where the string is actually stored a private member of the class. If you did this:

function StringBuilder() {
    this.buffer = [];
}

Then buffer is a public member and can be accessed via an instance. To make it private, simply declare buffer as a local variable inside StringBuilder. Like this:

function StringBuilder() {
    var buffer = [];
    
    this.getBuffer = function() {
        //
        // TODO:
        // return a copy so the original buffer is
        // left intact
        //
        return buffer;
    }
}

Now buffer is not visible to routines defined outside StringBuilder via an instance. But all methods defined inside StringBuilder can access buffer like any other member. You'd have to add accessor methods if you wished to provide access to private data. The same principle applies to member methods as well. Any local functions that you defined inside StringBuilder remain accessible only from other functions defined inside that class.

Cool eh?!

 

Please fill this form and click on the "Submit" button to post a comment.

 
Your Name :
Your Email :
Your Comment :
 
   
Please enter the code as shown above :
   

Please click here to go back to the blog.

blogorama home
about this blog
email the author
where on earth am i?
subscribe to mailing list
feeds Use these links for feed syndication
rss  |  atom
by category
technobabble (33)
philosophical crud (3)
irrelevant stuff (7)
archive
march, 2009 (2)
august, 2008 (2)
march, 2008 (1)
january, 2008 (1)
september, 2007 (2)
april, 2007 (1)
february, 2007 (2)
december, 2006 (1)
october, 2006 (1)
september, 2006 (4)
august, 2006 (3)
july, 2006 (4)
june, 2006 (3)
may, 2006 (6)
april, 2006 (2)
recent entries
Writing a sensor dr...
Enabling JSONP call...
The Conman
Memoization - Optim...
Random Lisp thought...
Learning Common Lis...
JavaScript closures...
Calling a JavaScrip...
88391 hits