Classes with private properties in JavaScript
JavaScript, a prototyped language, offers multiple ways to ‘emulate’ a classical class model. The best way to add methods to a constructor (class) function, is by extending its prototype object. However, all these properties are public, and can thus be accessed by anybody who has access to the object. It is somewhat less obvious to create a class that has private properties (methods or variables that are only accessible from within the class). I created a boilerplate class for the situations when I need this:
MyClass = function() {
// 'that' is used to access 'this' of MyClass from within private
// methods, because 'this' is then bound to the global object
var that = this;
// private variables
var privateVariable = 'I am private';
// public variables
this.publicVariable = 'I am public';
// private methods
var privateMethod = function() {
console.log('Private method entered');
console.log(privateVariable);
console.log(that.publicVariable); // note the use of 'that'
};
// public methods
this.publicMethod = function() {
console.log('Public method entered');
console.log(privateVariable);
console.log(this.publicVariable); // note the use of 'this'
privateMethod();
};
};
When you create an instance of MyClass, only publicVariable and publicMethod will be public properties. This can be confirmed by looping over all properties of an instance:
MyInstance = new MyClass();
var property;
// iterate over all public properties (variables and methods)
for (property in MyInstance) {
// print the property's name + type
console.log(property + ' : ' + typeof MyInstance[property]);
}
/* console output:
publicVariable : string
publicMethod : function
*/
Note that from within a private method, public properties are accessed through that. This is because of an unfortunate choice in the design of JavaScript which states that within all functions called directly, this is bound to the global object. This doesn’t happen when a function is called as a method (a property from another object), constructor (a class), or using the standard apply method of a function.
A disadvantage of above boilerplate code is that for each newly created instance of the class, the public and private properties are copied into memory for the new instance. This doesn’t happen when using prototypal inheritance - but then we are not able to make private properties easily.
There is a workaround for this, by having the constructor function (MyClass) return an object containing all the public properties. Private properties are accessible through the created closures. This also allows more advanced mechanisms such as super methods. To read more about inheritance in JavaScript, I suggest reading Chapter 5 of JavaScript: The Good Parts by Douglas Crockford.