1

I am reading Stoyan Stefanov's "Javascript Patterns". I am confused on the private static member section -- how does it works underlying.

var Gadget = (function () {
   var counter = 0;
   return function () {
       console.log(counter += 1);
   };
}());

var g1 = new Gadget(); // logs 1
var g2 = new Gadget(); // logs 2

Why "counter" becomes a static member?

Many thanks in advance!

4 Answers4

2

Gadget is a closure over counter. Whenever you call Gadget, 1 is added to counter.

It might be easier to see if you write the code as

var counter = 0;

var Gadget =  function () {
   console.log(counter += 1);
};

var g1 = new Gadget(); // logs 1
var g2 = new Gadget(); // logs 2

instead. It should be clear that there is only one counter variable and that its value is increased whenever Gadget is called.

The difference in your code is that it is wrapped in an IIFE, so that counter is not accessible from any other function other than the one returned from the IIFE (which is assigned to Gadget), thus making counter "private".

See also: What is the (function() { } )() construct in JavaScript?

Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
0

It becomes a static member, because it is not modified outside of the object. It isn't dynamic.

So, it becomes a static member.

In other words, all variables which are used inside an object, and which are not functions and properties, and which is used for internal logic is called static member.

Amit Joki
  • 58,320
  • 7
  • 77
  • 95
0

The reason is because the closure for the function returned by the immediate function includes a reference to the same counter for all instances of Gadgets. Things happen like this (roughly):

  1. The immediate function is immediately called (duh).
  2. The function returned will have a reference to 'counter'.
  3. When you call 'new Gadget()' an instance of Gadget is returned.

    a. This instance of Gadget is just another way of calling the function that gives an empty object for the 'this' and returns it as well. So g1 and g2 are blank objects.

    b. This means all instances will have a reference to 'counter'.

Erstad.Stephen
  • 1,035
  • 7
  • 9
0

It's private, because nothing outside the object that is created by the immediate execution of the anonymous function whose definition starts on line 1 can access the variable counter.

It's not really static, because, if Gadget is defined in an inner scope, the storage used for Counter could be garbage-collected once Gadget and all of the Gadget objects that it has created have been discarded. But it behaves like static for most purposes when used at the top level.

Confusingly, this code in the more complete example that follows does not do what Stefanov says.

var Gadget = (function () {
    var counter = 0, NewGadget;
    NewGadget = function () {
        counter += 1;
    };
    NewGadget.prototype.getLastId = function () {
        return counter;
    };
    return NewGadget;
}()); // execute immediately

var iphone = new Gadget();
iphone.getLastId(); // 1
var ipod = new Gadget();
ipod.getLastId(); // 2
var ipad = new Gadget();
ipad.getLastId(); // 3

He writes: "Because we’re incrementing the counter with one for every object, this static property becomes an ID that uniquely identifies each object created with the Gadget constructor.". That's just wrong. There is only one counter, and all of the Gadget objects have a reference to it. The function getLastId() does just what its name suggests: gets the most recently issued id, and not the value of counter when the gadget was created.

So, the above example runs, and produces the results indicated by the comments. But if you try

    iphone.getLastId(); // 3

one more time, you get 3 — the current value of counter, not the value when iPhone was created.

To get the effect of each Gadget having a unique id, we can use a fresh variable for each Gadget, like this:

var Gadget = (function () {
    var counter = 0, NewGadget;
    NewGadget = function () {
        counter += 1;
        var myId = counter;
        this.myUid = function () {
            return myId;
        };
    };
    return NewGadget;
}()); // execute immediately

var iphone = new Gadget();
iphone.myUid(); // 1
var ipod = new Gadget();
ipod.myUid(); // 2
var ipad = new Gadget();
ipad.myUid(); // 3
iphone.myUid(); // 1

Note that myId is definitely not static, even though we are using the same pattern as for counter. However, it is private. There is a separate myId for each Gadget, and it's not a property of the Gadget object — it's truly hidden. But the object's myUid function has closed over it.