One curiosity in our code base are comments in JavaScript files, stating that this variable or function is private. Well, just putting a comment there doesn’t make a variable private, right?
So how to do it?
For that you first need some understanding of scope and closure in JavaScript. In Java, C# or Ruby you deal with block scoped variables. Below a C# example:
public void aFunction()
{
string a = "value1";
if (true)
{
string b = "value2";
}
a = b;
}
So the string variable a is accessible within the if-statement, but the assignment a = b will cause an exception, because b exists just within the scope of the if-statement.
That’s different in JavaScript. In JavaScript the next code doesn’t cause an exception:
var global = 10;
function aFunction() {
var a = "value1";
if (true) {
var b = "value2";
}
a = b;
return a;
}
var test = aFunction();
All declared variables in JavaScript are function scoped. So both, a and b, are accessible from everywhere within the definition of aFunction. Variables declared outside of any function are global and thus accessible just everywhere. In fact they become members of the global window object. You really should keep the amount of globals small, otherwise you’ll enter the world of pain when your code grows.
Alright, so we covered scope in JavaScript. Rather in a compact way, but well enough. Let’s move on to closures and consider the next code fragment:
1
2
3
4
5
6
7
8
9
10
| var myModule = function(){
var internal = 5;
return {
publicProperty: "publicText"
, getInternal: function() {
return internal;
}
}
}(); |
This looks pretty much like we assign an anonymous function to the variable myModule. But take a closer look! In fact, we assign the return value of that function to the variable. Note the parenthesis in line ten which executes the anonymous function directly.
The return value is an object literal holding two fields: publicProperty and getInternal. Let’s play with that:
1
2
3
4
5
6
7
8
9
10
| var test1 = myModule.getInternal();
// test1 will be equal to 5 after assignment.
var test2 = myModule.publicProperty;
// test2 will be equal to "publicText" after assignment
// the next line will cause an error, depending on the
// browser you're using it's different
// but the message is that internal is undefined.
var test3 = myModule.internal; |
Most likely you’re not surprised that the assignment in line 4 works. But how does line 1 work? The anonymous function was directly executed, so it already ended and you would expect the variable internal doesn’t exist any more at the point you call myModule.getInternal(). Well, that’s exactly what we call a closure. The variable “internal” didn’t die with the end of the execution of the anonymous function. It’s still in memory, but can’t be accessed other than by functions which were defined within the same scope, like our getInternal function.
As the code above implies you can use this behavior in JavaScript to define private properties, which you can expose by public functions but which are not accessible if not exposed. Besides to the fact that you can realize private function and properties with this technique, using modules / namespaces is a good idea to keep the amount of globals small. Libraries like Prototype use this technique.
You know now, how to write a module in JavaScript and how to realize private members. There are a lot more cool things around this topic and if you’re curious I strongly recommend the reading of Douglas Crockfords articles about JavaScript.