Friday, May 14, 2010

* How to emulate private instance variables in javascript

It is easy to emulate private instance method in javascript (by
defining a named function and call/apply it on "this"), but not as
easy to emulate private instance variables, especially when you are
using prototype to define public instance methods for a class. This
article provides a working solution to this problem.

First, if we are not using prototype, then the following works:

var fooClass = function() {
var pvar1;
var pvar2;

this.barMethod = function() {
pvar2 = pvar1 + 1;
this.kaz = pvar1 * pvar2;
... ...
};
};

In this piece of code, both pvar1 and pvar2 are local variables that
can only be access in the scope of defining fooClass. However, the
problem is that for each object created using the constructor
fooClass, a new copy of the barMethod will be constructed, which is a
waste.

In order to solve this problem, prototype can be used:

var fooClass = function() {
var pvar1;
var pvar2;
};

fooClass.prototype.barMethod = function() {
pvar2 = pvar1 + 1;
this.kaz = pvar1 * pvar2;
... ...
};

But now, the private instance variables are out of scope, so this
program will never work.

Essentially, in the prototype definition, the ONLY way to refer back
to the current object is through the magical keyword "this". So an
instance variable must be referred through "this", which will enforce
it to be public. That is a limitation of javascript which cannot be
overcome.

But that is not the end of the story. If we cannot totally hide the
visibility of an instance variable from "this", we can at least hide
its identity so that it is impossible for outsiders to uncover it.
Here is what we can do:

var fooClass = function() {
var pvar1 = randomName();
var pvar2 = randomName();

var _fooClass = function() {
this[pvar1] = 1;
this[pvar2] = 2;
};

_fooClass.prototype.barMethod = function() {
this[pvar2] = this[pvar1] + 1;
this.kaz = this[pvar1] * this[pvar2];
... ...
};
return _fooClass;
}();

This way, it is clear that in there exists two public instance
variables of some random name in "this" object, and they can be
referred in the scope of defining fooClass through references to those
random names. But these "public" instance variables are practically
not accessible from outside the scope of defining fooClass because
ideally, nobody could guess what the random names are.