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.