Stepan Loginov
Stepan Loginov

Reputation: 1767

Static private field Javascript

I need constructor that initialize some Objects with unique name. I write some code like this:

Obj.prototype.idCounter = 0;
Obj = function() {
   this.name = "Obj_" + Obj.prototype.idCounter;
   Obj.prototype.idCounter++;
}

var o1 = new Obj();
var o2 = new Obj();
alert(o1.name); // Obj_0
alert(o2.name); // Obj_1

But Obj.prototype.idCounter is non-private. I know how to create private variable, but I have no idea how to make private static variable.

Upvotes: 1

Views: 71

Answers (3)

Pointy
Pointy

Reputation: 413702

What you can do is this:

var Obj = function() {
    var idCounter = 0;

    function Obj() {
       this.name = "Obj_" + idCounter;
       idCounter++;
    }
    return Obj;
}();

Now idCounter is a local variable to that anonymous function, so nothing else can see it except for the constructor function.

Note that you can also do some initialization of the prototype object in there too:

var Obj = function() {
    var idCounter = 0;

    function Obj() {
       this.name = "Obj_" + idCounter;
       idCounter++;
    }
    // one way to add a prototype property, and not
    // the simplest
    Object.defineProperties(Obj.prototype, {
      getInstanceCount: {
        value: function() {
          return idCounter;
        }
      }
    });
    return Obj;
}();

Now when you have an instance of Obj you can call getInstanceCount() to get a total number of objects created (which would be a weird way to design an API but it's just to illustrate that the prototype functions may get access to those private variables too).

Upvotes: 3

Tamas Hegedus
Tamas Hegedus

Reputation: 29906

In JavaScript, you usually prefix field names with an underscore _ to indicate they are private. Of course this does not make them really private, but developers should show some self-discipline and consider it as private.

function Obj() {
  this.name = "Obj_" + (Obj._idCounter++);
}
Obj._idCounter = 0;

var o1 = new Obj();
var o2 = new Obj();
log(o1.name); // Obj_0
log(o2.name); // Obj_1

function log(x) { var p = document.createElement('pre'); p.appendChild(document.createTextNode(x)); document.body.appendChild(p); }

If you really want to hide something you can of course use closures, as others stated. However that is a bit harder to debug and for some reason that is a bit slower.

Upvotes: 0

axelduch
axelduch

Reputation: 10849

There is no way (as far as I know) to replicate private static members the way you described it.

What you could do to solve the problem of keeping your id generator safe is to use the module pattern, and use a sort of privileged access to it from within the module scope.

// using an immediately invoked function to generate the isolated scope
var Obj = (function () {
    var idCounter = 0;

    return function Obj() {
        this.name = "Obj_" + idCounter;
        idCounter++;
    };
}());

var o1 = new Obj();
var o2 = new Obj();
alert(o1.name); // Obj_0
alert(o2.name); // Obj_1

Upvotes: 3

Related Questions