views:

374

answers:

3

After reading a bit on Javascript's prototypical inheritance model, I change my style of constructing a class from

var Some_Class = function() {
    this.public_method = function() {
    };
    (function() {
        // constructor
    }).call(this)
}

to

var Some_Class = function() {
    (function() {
        // constructor
    }).call(this)
}
Some_Class.prototype.public_method = function() {
};

Although I understand that this is a good practice, but I am not allowed to access private methods from the public method anymore

var Some_Class = function() {
    var private_member = 'whatever';

    (function() {
        // constructor
    }).call(this)
}
Some_Class.prototype.public_method = function() {
    return private_member; // not possible
};

After reading through an article here (Closure-created constructor), then I came out with this

var Some_Class = function() {
    var private_member = 'whatever',

    private_method = function(_some_value) {
        // private method implementation
    };

    if(!arguments.callee.prototype.public_method) {
        arguments.callee.prototype.public_method = function() {
            private_method.call(this, private_method);
        };
    }

    (function() {
        // constructor
    }).call(this)
}

However, what are the drawbacks of doing this?! or is there a better way of doing this if I want to access private member in the public method?

+3  A: 

The use of function scope variables and closures to simulate private variables/functions is a well established idiom in the javascript community. If the variable is truly intended to be private, I see no drawback to this approach (although some claim that performant code on certain browsers/hosts has to pay attention to how many closures get created).

In your example, the private_method (and its environment) is shared across all objects - since your public_method closure is created only the first time the object is constructed (and bound to the constructor's prototype property that sets the created object's internal prototype chain) - so the private_method that is used is only the one that was created the first time.

Here is some sample code that will help illustrate what is going on:

  var global = 1;

  var Some_Class = function() {
    var private_method = 'whatever';
    var now = ++global;
    print("outer now: " + now );
    private_method = function(_some_value) {
        // private method implementation
        print("inner now: " + now);
    };

    if(!arguments.callee.prototype.public_method) {
        arguments.callee.prototype.public_method = function() {

            private_method.call(this, private_method);
        };
    }

    (function() {
        // constructor
    }).call(this)
}

new Some_Class().public_method(); // outer now: 2, inner now: 2
new Some_Class().public_method(); // outer now: 3, inner now: 2
new Some_Class().public_method(); // outer now: 4, inner now: 2

Are you sure that is what you want?

If your private_method does not need to refer to the enclosing object's state, then I see little benefit in doing things the way you are doing.

What I usually do (if i have to use 'new' to create my object) is the following:

function MyClass() {
  var private_var = 1; 
  function private_func()
  {

  }
  this.public_func = function() 
  {
     // do something
     private_func();
  }
  this.public_var = 10;
}

var myObj = new MyClass();

The downside to this approach is that each time you construct the object via 'new' you re-create all the closures. But unless my profiler tells me that this design choice needs to be optimized, i prefer its simplicity and clarity.

Also I don't see the benefit in your code of doing the following either:

  (function() { }).call(this);  // call the constructor

Why are you creating a separate scope in your constructor?

Faisal Vali
thanks for clearing that up, for the second question... I guess it is probably because I am still not very much familiar to the object model and wanting to make my code similar to OOP code in php/java/other OOP programming language
Jeffrey04
+4  A: 

My answer is a non-answer: there's no built-in private access in JavaScript but that's okay because YAGNI. Here's how I make private members in my code:

function Some_Class() {
    this._private_member = 'whatever';
}

Some_Class.prototype._private_method = function() {
};

That's good enough. It's not really worth it to jump through hoops when the only real purpose of private is to protect yourself from... yourself.

(I say this having spent many hours myself playing around with every permutation of closures and prototyping, just as you are, and finally saying "screw it, it's not worth it".)

John Kugelman
I agree. Forcing fake private access in languages that don't support it usually means UR DOING IT RONG.
Triptych
@Triptych - while i generally agree that if you have to fight a well designed language to do what you want to do, then you should really reconsider your design. But, in this case, simulating private access through function scope variables and closures is endorsed as a natural javascript idiom by many well-established and seasoned javascript programmers.
Faisal Vali
+1  A: 

If you have not done so already have a look at this JavaScript Module Pattern, which allows you to access private methods and variables from within the public functions, etc.

Ian Oxley
:D I have read about it before, just that for some reason I don't quite like singleton pattern and wants to find an alternative way...
Jeffrey04