wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

JavaScript Closures


XPages allow you to use JavaScript closures in both client and server side code. There are plenty explanations available, which seem to make them rather more mysterious. After looking at a lot of them I conclude: " JavaScript closures are like riding a bicycle: nearly impossible to explain, but obvious and natural once you get it". So here is my try, from a LotusScript perspective.
First step in the puzzle is the fact, that there is no difference in JavaScript between a function and a class. To get an instance of a class/function you simply call the function with new:
var myInstance = new MyFunction();
The second piece is the fact that calling a function is the equivalent of calling the default method of a class instance. Default methods are absent from Java, dotNet or LotusScript, but were available in VB (typically .text). So myInstance() actually is myInstance.defaultMethod(). The third piece is to understand the functions that return a function/object as sort of factory pattern with an abbreviated syntax. In LotusScript you would write something like:

  
  
Option Public Option Declare %REM Class BaloonFactory Description: Creates all sort of Ballons %END REM Public Class BaloonFactory Private currentGas As String Private currentColor As String Public Sub New me .color = "Red" me .gas = "Helium" End Sub Public Property Set Color As String me .currentColor = Color End Property Public Property Set Gas As String If Gas < > "Helium" And Gas < > "Hydrogen" Then me .currentGas = "Helium" 'Let us play save Else me .currentGas = Gas End If End Property Public Function makeBaloon As Baloon Set makeBaloon = New Baloon ( me .currentColor , me .currentGas ) End Function End Class %REM Class Baloon Description: We like them in a lot of colors %END REM Public Class Baloon Private currentGas As String Private currentColor As String Public Sub New (Color As String , Gas As String ) me .currentColor = Color me .currentGas = Gas End Sub Public Sub POP MsgBox "You popped a " + me .currentColor + " baloon filled With " + me .currentGas End Sub End Class %REM Sub Demo Description: Comments for Sub %END REM Public Sub Demo Dim factory As New BaloonFactory Dim b As Baloon Dim r As Baloon Dim g As Baloon Set r = factory .makeBaloon ( ) factory .Color = "Blue" Set b = factory .makeBaloon ( ) factory .Color = "Green" Set g = factory .makeBaloon ( ) Call r .POP ( ) Call b .POP ( ) Call g .POP ( ) End Sub
This LotusScript was converted to HTML using the ls2html routine,
provided by Julian Robichaux at nsftools.com.
In JavaScript you would write something like:
1:  function BaloonFactory() {  
2:       var curColor = "red";  
3:       var curGas = "Helium";  
4:       this.setColor = function(newColor) {  
5:            curColor = newColor;  
6:       };  
7:       this.setGas = function(newGas) {  
8:            if (newGas == "Helium" || newGas == "Hydrogen" ) {  
9:                 curGas = newGas;  
10:            } else {  
11:                 curGs = "Helium";  
12:            };  
13:       };  
14:       this.makeBaloon= function() {  
15:            var baloon = {  
16:                  "trueColor" : curColor,  
17:                 "POP" : function () {  
18:                      alert("You popped a " + curColor + " baloon filled with " + curGas + " (or was it "+this.trueColor+"?)");  
19:                 }
20:            };
21:            return baloon;
22:       }
23:  }  
24:  function demo() {  
25:       var factory = new BaloonFactory();  
26:       var r = factory.makeBaloon();  
27:       factory.setColor("Blue");  
28:       var b = factory.makeBaloon();  
29:       factory.setColor("Green");  
30:       var g = factory.makeBaloon();
31:       factory = null;  
32:       r.POP();  
33:       b.POP();  
34:       g.POP();  
35:  }  

Do you spot the difference? In LotusScript all variables must be maintained inside the ballon. The baloon has no access to the factory once released. In a JavaScript closure the new object has still access to the factories variables (see line 18) even once the factory is gone (see line 31). As long as the factory object exists updates to the inner variables of that factory are updated in the baloon too. To have unique values you would pass these values as parameters to the factory method or constructor:
1:       this.makeColorBaloon= function(newColor) {  
2:            var baloon = {  
3:                 "POP" : function () {  
4:                      alert("You popped a " + newColor + " baloon filled with " + curGas);  
5:                 }
6:            };
7:            return baloon;
8:       }  
9:  var y = factory.makeColorBaloon("Yellow");  
10:  y.POP();  

Posted by on 20 February 2010 | Comments (1) | categories: Show-N-Tell Thursday

Comments

  1. posted by Thomas Bahn on Friday 05 March 2010 AD:
    "the fact, that there is no difference in JavaScript between a function and a class."

    There aren't classes in JavaScript. You can use some functions as constructors, though.


    "To get an instance of a class/function you simply call the function with new: var myInstance = new MyFunction();"

    new creates a new, empty object and runs MyFunction in the contect of this object.

    In this execution of the constructor "this" references the newly create object.

    If a constructor doesn't return with "return something" and something is an object, it returns the newly created object.


    "The second piece is the fact that calling a function is the equivalent of calling the default method of a class instance. Default methods are absent from Java, dotNet or LotusScript, but were available in VB (typically .text). So myInstance() actually is myInstance.defaultMethod()."

    In fact, there are at least for ways to call a function in JavaScript.

    MyFunction()
    The function is executed in the context of the global object.

    myInstance.MyFunction()
    The function is executed in the context of the myInstance object.

    var myInstance = new MyFunction()
    A new, empty object is created and the function executed in the context of the new object.

    myInstance.MyFunction.apply(otherObject, ...)
    The function is executed in the context of otherObject.


    "The third piece is to understand the functions that return a function/object as sort of factory pattern with an abbreviated syntax."

    In my opinion, the factory pattern is more about one object (or class) creating objects depending on the status of the system (global vars, environment, other objects' values) and parameters. Just returning a function or object isn't enough to qualify... Emoticon wink.gif

    Ciao
    Thomas