Question

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?

Was it helpful?

Solution

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?

OTHER TIPS

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".)

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.

Echoing John Kugelman: It's impossible to create private members in javascript. Live with it. Even if you create a enclosure like this:

function SomeClass() {

   var _private = 0;
   this.public_acessor = function() {return _private};
}

Any user can still write:

SomeClass._not_private_anymore = 1;
SomeClass.public_acessor = function () {return this._not_private_anymore}; 

In the end, you can't trust any public member to be the same you declared. If someone is up to break your code, he will! Another user won't break your code only because it's useful.

Works with prototype, not just singleton. Problem is, when it's time to subclass, my subclass has no access to the privates

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