JavaScript Class Patterns Revisited: Endgame
- by Liam McLennan
I recently described some of the patterns used to simulate classes (types) in JavaScript. But I missed the best pattern of them all. I described a pattern I called constructor function with a prototype that looks like this: function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype = {
toString: function() {
return this.name + " is " + this.age + " years old.";
}
};
var john = new Person("John Galt", 50);
console.log(john.toString());
and I mentioned that the problem with this pattern is that it does not provide any encapsulation, that is, it does not allow private variables. Jan Van Ryswyck recently posted the solution, obvious in hindsight, of wrapping the constructor function in another function, thereby allowing private variables through closure. The above example becomes:
var Person = (function() {
// private variables go here
var name,age;
function constructor(n, a) {
name = n;
age = a;
}
constructor.prototype = {
toString: function() {
return name + " is " + age + " years old.";
}
};
return constructor;
})();
var john = new Person("John Galt", 50);
console.log(john.toString());
Now we have prototypal inheritance and encapsulation. The important thing to understand is that the constructor, and the toString function both have access to the name and age private variables because they are in an outer scope and they become part of the closure.