Implementing private instance variables in Javascript
Privates are expensive, avoid them if possible
Private doesn't exist. You can do one of two things to emulate this.
- closures
- Weakmaps
Closures
function makePrinter(word) {
return {
print: function () {
console.log(word)
}
}
}
WeakMap
Browser support for weakmaps is awful. You will probably need an emulation, I recommend pd.Name
var Printer = (function () {
var privates = function (obj) {
var v = map.get(obj)
if (v === undefined) {
v = {}
map.set(obj, v)
}
return v
}, map = new WeakMap()
return {
constructor: function (word) {
privates(this).word = word
},
print: function () {
console.log(privates(this).word)
}
}
}());
Sensible objects
var Printer = {
constructor: function (word) {
this._word = word
},
print: function () {
console.log(this._word)
}
}
A slight modification to the code using this
will work. The correct instance of Printer.prototype.print
was not being instantiated for the a
object.
var Printer = (function(){
var _word;
Printer = function(word){
this._word = word;
}
_print = function(){
console.log(this._word);
}
Printer.prototype = {
print: _print
}
return Printer;
})();
var a = new Printer("Alex");
var b = new Printer("Bob");
a.print(); //Prints Alex
b.print(); //Prints Bob
You're doing some wonky stuff with that closure. _word
needs to be declared in the Printer
function, not lost in anonymous-closure land:
function Printer(word) {
var _word = word;
this.print = function () {
console.log(_word);
}
}
var a = new Printer("Alex");
var b = new Printer("Bob");
a.print(); //Prints Alex
b.print(); //Prints Bob
This keeps _word
private, at the expense of creating a new print
function on every Printer
instance. To cut this cost, you expose _word
and use a single print
function on the prototype:
function Printer(word) {
this._word = word;
}
Printer.prototype.print = function () {
console.log(this._word);
}
var a = new Printer("Alex");
var b = new Printer("Bob");
a.print(); //Prints Alex
b.print(); //Prints Bob
Does it really matter that _word
is exposed? Personally, I don't think so, especially given the _
prefix.