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:
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:
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:
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 Stephan H Wissel on 20 February 2010 | Comments (1) | categories: Show-N-Tell Thursday