Finally, it’s time to finish up the lesson on private static members and methods in JavaScript.
Last time, I introduced the technique of creating and immediately executing a function, using parentheses. I talked a little about returning a function and storing it in a variable.
1.
var myFunc = (function(){
2.
returnfunction(){
3.
alert("Hello, World!");
4.
}
5.
})();
6.
7.
alert(myFunc); // "function () … "
8.
9.
myFunc(); // Hello, World!
There are a lot of things you can do with this trick, like create interesting [bookmarklets](http://coffeeonthekeyboard.com/firefox-open-in-blank-tab-197/). But let’s see how you can use it to protect information on the class level.
Here we’ll take advantage of JavaScript’s scope behavior. Remember that a function uses the variables where it is defined, not executed. Perhaps a better example…
1.
var myFunc = (function(){
2.
var message = "I’m hidden.";
3.
returnfunction(){
4.
alert(message);
5.
}
6.
})();
7.
8.
var message = "I’m visible.";
9.
10.
myFunc(); // "I’m hidden."
We can see that the inner function (which is returned from the outer function and set to `myFunc`) uses the value of `message` from the block where it was defined, not executed.
Now you should be able to see where this is going. Let’s look at a more complex example, extended from the first part:
1.
var Product = (function(){
2.
var partNumRegex = /^\d{4}\-\d{2}$/;
3.
4.
returnfunction( num )
5.
{
6.
var partNum = null;
7.
8.
this.setPartNum = function( n )
9.
{
10.
if(partNumRegex.test(n)){
11.
partNum = n;
12.
returntrue;
13.
}else{
14.
returnfalse;
15.
}
16.
}
17.
18.
this.getPartNum = function()
19.
{
20.
return partNum;
21.
}
22.
23.
if(num)this.setPartNum(num);
24.
25.
returnthis;
26.
}
27.
})();
28.
29.
var car = new Product;
30.
car.setPartNum(‘1234-56’);
31.
32.
var table = new Product;
33.
table.setPartNum(‘345678’);
34.
35.
alert("Car: "+car.getPartNum()); // "Car: 1234-56"
36.
alert("Table: "+table.getPartNum()); // "Table: null"
What’s the advantage here? The variable `partNumRegex` is *not* copied by the `new` operator. In a small example like this, there is not much benefit, but if you had hundreds of `Product` objects, you could save a significant amount of memory.
There are a few major drawbacks: a public static (class) method cannot access a private static method or variable. For example:
1.
var Product = (function(){
2.
var partNumRegex = /^\d{4}\-\d{2}$/;
3.
4.
returnfunction(){
5.
// snip
6.
}
7.
})();
8.
9.
Product.validPartNum = function(num){
10.
if(partNumRegex.test(num)){// (1)
11.
returntrue;
12.
}
13.
returnfalse;
14.
}
The class method `validPartNum` has no access to the private class variable `partNumRegex`, and so will throw an error at (1). Adding an accessor *must* be done on the *instance*, not the class, like so:
1.
var Product = (function(){
2.
var partNumRegex = /^\d{4}\-\d{2}$/;
3.
4.
returnfunction(){
5.
this.getPartNumRegex = function(){
6.
return partNumRegex;
7.
}
8.
9.
// snip
10.
}
11.
})();
But then you cannot access the private variable without first creating an instance of the class, and the accessor function is copied with the `new` operator. New methods added to the `Product.prototype` object are likewise unable to access the private static variables. This is a limitation of JavaScript.
Even with these limitations, the ability to hide implementation behind an agreed-upon interface is powerful. (JavaScript doesn’t actually have interfaces, but you can just write it down.) Behind the scenes, you could load new data via Ajax, without ever exposing your Ajax method to that new guy down the hall who likes to misuse everything he can:
1.
var Product = (function(){
2.
var partNumRegex = /^\d{4}\-\d{2}$/;
3.
4.
// private static function, not copied with "new"
5.
function loadPartData(partNum){
6.
// load data via Ajax
7.
}
8.
9.
returnfunction(){
10.
11.
var partNum = null;
12.
13.
// snip
14.
15.
this.setPartNum(num){
16.
if(partNumRegex.test(num)){
17.
partNum = num;
18.
var data = loadPartData(partNum);
19.
this.productName = data.productName;
20.
this.price = data.price;
21.
returntrue;
22.
}else{
23.
returnfalse;
24.
}
25.
}
26.
27.
// snip
28.
}
29.
})();
That’s it for now. I owe most of these three articles to the book [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X), by Ross Harmes and Dustin Diaz. Those two are geniuses, and anyone who wants to be a better JavaScript programmer would do well to pick up their book.
Next up, I’ll argue why the <dl>
tag is a good way to display forms semantically.