Question

This question is about the behavior of an object with methods added to its prototype chain and a few private variables. Just out of curiosity and to get my head around this riddle.

function SomeObject() {
    if (this instanceof SomeObject) {
      var args  = arguments[0],
          proto = SomeObject.prototype,
          privatevalue = 0,
      /** assign first element of args[0] 
        * (=instance name) to private variable [id],
        * to be able to keep track of the instance
        */
          id = args[0] ||'no id';


      /** public 'set' adds a value to
        * the private variable [privatevalue]
        */
      this.set =
         function(){
           privatevalue += arguments[0] || 1;
           return privatevalue;
          };
       /** toString functions as a kind of getter */
       this.toString = function(){
            return id+' privatevalue: '+privatevalue;
       }

       /** add two methods to the prototype chain 
         * this happens only once
         */
       if (!proto._initialized_) {
         /** SomeObject.prototype.add 
           * uses 'this.set' to add a value
           * to [privatevalue] and returns
           * the object value (from tostring)
           */
         proto.add =
           function(){
             this.set(arguments[0]);
             return this;
         };
         /** SomeObject.prototype.add2 
           * uses 'this.set' to add a value
           * to [privatevalue] but returns
           * a string using private variables
           * [id] and [privatevalue] 
           */
         proto.add2 =
            function(){
              this.set(arguments[0]);
              return id+' privatevalue: '+privatevalue;
         };
         proto._initialized_ = true;
        }

        } else {
           return new SomeObject(Array.prototype.slice.call(arguments));
        }
  }

  /** create 2 instances of SomeObject */
  var objA = SomeObject('objA'),
      objB = SomeObject('objB');

  /** show the values and use the prototype [add] method
    * to change [privatevalue]
    */
  alert ([objA, objB].join(' | ')); 
        //=> objA privatevalue: 0 | objB privatevalue: 0
  alert ([objA.add(4), objB.add(2)].join(' | ')); 
         //=> objA privatevalue: 4 | objB privatevalue: 2

  /** use prototype method 'add2' to change and view the
    * private variables [id] and [privatevalue] for objA
    */
  alert (objA.add2()); 
         //=> objB privatevalue: 2!

Now the question is: why does the prototype method add2 from ojbA (thus: objA.add2()) return the values of the private variables from objB? I would say these privates shouldn't be accessible for objA. In other words: what kind of scoping is going on here? Stranger still. If you do this:

  alert (objA.add2()); 
  alert (objB.add2());

you get for objA.add2(): objA privatevalue: 5 and for objB.add(): objA privatevalue: 5

Was it helpful?

Solution

The problem is the scope in which you create the add functions.

They are created in the scope of SomeObject execution when you instantiate 'objA'.

Hence id and privatevalue variables accessed by Add2 are the ones belonging to 'objA' regardless of whether you call .Add2 agains 'objA' or 'objB'.

Fundementally prototype based methods cannot to access private members of a class. In order to access private members a function needs to be created in the same scope (or a child scope) of those members. This is why set works because its created on each instantiaion of SomeObject.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top