1

I have a function defined in javascript that acts as a class. Within it, I have several public methods defined, but there is one private method, and I need to access one of the public methods within it.

function myClass(){ 
   this.myPublicMethod = function(a,b){
       var i = a*b;
       return i;
   }

   function myPrivateMethod(){
        var n = this.myPublicMethod(2,3);
   }
}

This doesn't work. Is there a way to access myPublicMethod within myPrivateMethod?

9
  • 1
    How is the private method called? Commented Oct 8, 2013 at 0:16
  • Make sure to have a look at my answer ;) Commented Oct 8, 2013 at 0:22
  • Oh my, we're talking about "private" methods (not instance specific), you can put those on the prototype together with the "privileged" methods that need to call them. Can't believe how wrong the answers here are. If you need instance specific "private" members than you'll have to throw out prototype all together and can use a function to return an object containing closures. The latter is very bad design in my opinion and the first I never used but am aware of it's existence. Current standard is to define "private" methods by their name starting with low dash: _privateMember Commented Oct 8, 2013 at 5:42
  • @HMR I would not say "current standard". Commented Oct 8, 2013 at 9:22
  • 1
    @HMR Now I understand in what sense you use the word "standard" :). Commented Oct 8, 2013 at 10:44

7 Answers 7

2

You simply have to specify the value of this when calling your private method using Function.prototype.call.

myPrivateMethod.call(this);

E.g.

function myClass(){ 
   this.myPublicMethod = function(a,b){
       var i = a*b;
       return i;
   }

   function myPrivateMethod(){
        var n = this.myPublicMethod(2,3);
   }

   //calling private method in the *scope* of *this*.
   myPrivateMethod.call(this);
}

Please note that having true private members (that aren't functions) comes at the cost of not taking advantages of prototypes. For that reason, I prefer to rely on naming conventions or documentation to identify private members rather than enforcing true privacy. That holds only for non-singleton objects.

The following example demonstrates what is being said above.

//Constructors starts by an upper-case letter by convention
var MyClass = (function () {

    function MyClass(x) {
        this._x = x; //private by convention
    }

    /*We can enforce true privacy for methods since they can be shared
    among all instances. However note that you could also use the same _convention
    and put it on the prototype. Remember that private members can only be 
    tested through a public method and that it cannot be overriden.*/
    function myPrivateMethod() {
        this.myPublicMethod1();
    }

    MyClass.prototype = {
        constructor: MyClass,
        myPublicMethod1: function () {
            //do something with this._x
        },
        myPublicMethod2: function () {
            /*Call the private method by specifying the *this* value.
            If we do not, *this* will be the *global object* when it will execute.*/
            myPrivateMethod.call(this);            
        }
    };

    return MyClass;

})();
Sign up to request clarification or add additional context in comments.

2 Comments

Not that I ever use it but added the correct module pattern for having privileged methods that can call "private" methods. The OP didn't have instance specific privates so no point in having everything in the constructor body.
@HMR, I added a code example that puts some more emphasis on the note I had written.
1

You can try this to defeat the local scoping:

function myClass(){ 

   this.myPublicMethod = function(a,b){
       var i = a*b;
       return i;
   }
   // Capture the original context of `this` myClass
   var self = this;
   function myPrivateMethod(){
        var n = self.myPublicMethod(2,3);
   }
}

We use self to maintain a reference to the original this even as the context is changing (since we want to call the public method int the private method).

1 Comment

Not that I ever use it but added the correct module pattern for having privileged methods that can call "private" methods. The OP didn't have instance specific privates so no point in having everything in the constructor body.
1

One way to do this is defining every method as private first, and making the ones you want public in the end (myPrivateMethod will reference the original myPublicMethod even if myClass.myPublicMethod is overridden):

function myClass(){ 
   var myPublicMethod = function(a,b){
       var i = a*b;
       return i;
   }

   var myPrivateMethod = function (){
        var n = myPublicMethod(2,3);
   }

   this.myPublicMethod = myPublicMethod;
}

6 Comments

Ill probably do this in my next project.
@WilliamOliver There are lots of different styles available. You should decide whether you need constructors at all... simple object literals could be enough and you can use Object.create() for "inheritance". If you want to use constructors, you can also try returning a crafted object from the constructor.
Note that this works only if the private method doesn't rely on this.
I apologize for my answer, I didn't read your question thoroughly enough.
Not that I ever use it but added the correct module pattern for having privileged methods that can call "private" methods. The OP didn't have instance specific privates so no point in having everything in the constructor body.
|
0

You could write

var myPublicMethod = this.myPublicMethod = function()...

So there was a private and a public instance created.

Just seems cleaner to me.

2 Comments

The latter doesn't create a local variable.
@Bergi, Oops! I forgot. Thanks.
0

You could potentially pass the public function to the private function as a parameter and then call it.

this.myPublicMethod = function(a,b){
   alert(a * b);
}

function myPrivateMethod(publicMethod){
    var n = publicMethod(2,3);
}
myPrivateMethod(this.myPublicMethod);

Here is a working fiddle.. http://jsfiddle.net/rxtB2/3/

Comments

0

An alternative to invoking call could be to attach the method directly to the myClass Function object.

function myClass(){ 

   myClass.myPublicMethod = function(a,b){
       var i = a*b;
       return i;
   }

   this.myPublicMethod = myClass.myPublicMethod;

   function myPrivateMethod(){
        var n = myClass.myPublicMethod(2,3);
        return n;
   }

   console.log("Calling myPrivateMethod()");
   console.log(myPrivateMethod());

}

1 Comment

Not that I ever use it but added the correct module pattern for having privileged methods that can call "private" methods. The OP didn't have instance specific privates so no point in having everything in the constructor body. And yes, if you use the pattern correctly you have to use call or apply because the privileged and private methods are on the prototype thus this is unknown at the time of declaring them.
0

If you only want "private" methods then your pattern for defining it is wrong. I think methods that can access "private" methods are called privileged methods but can be wrong.

The pattern for creating them is the following (added instance variables and inheritance in the example):

// added to show inheritance
var Parent = function(){
  //instance members
  this.parentInstanceVar=["parent"];
};
var Class = function() {
  //1st step to "inherrit" from Parent
  // take ownership of Parent instance members
  Parent.call(this);
  //to pass all arguments to Parent constructor:
  //Parent.apply(this,arguments);
  //to pass specific agruemtns to Parent
  //Parent.call(this,arg1,arg5);
  this.someIntanceVar=["Class instance"];
};
Class.prototype=(function(parent){
  var ret=(parent&&parent.prototype)?
    Object.create(parent.prototype):
    Object.create({});
  //repair the constructor
  ret.constructor=Class;
  var myPrivateMethod = function() {
    return this.someIntanceVar;
  };
  //privileged method calling "private method"
  ret.myPriviligedMethod=function(){
    return myPrivateMethod.call(this);
  };
  return ret;
}(Parent));//2nd step to "inherit" from Parent
//non privileged method
Class.prototype.nonPrivileged=function(){
  //can't accesss myPrivateMethod here
};

//some tests creating 2 instances
var c1=new Class();
var c2=new Class();
c1.parentInstanceVar.push("added in c1");
c1.someIntanceVar.push("added in c1");
console.log(c2.parentInstanceVar);//=["parent"]
console.log(c2.someIntanceVar);//=["class instance"]
console.log(c1.myPriviligedMethod());//=["Class instance", "added in c1"]
console.log(c2.myPriviligedMethod());//=["Class instance"]
//reason why we repaired the constructor:
console.log((new c1.constructor()) instanceof Class);//=true

This pattern only handles instance shared private members. If you need instance specific private members you can't use prototype for any privileged methods (methods that need access to "private" instance specific members). You can use use a function that returns an object containing closures but I would really not use this pattern as it ignores prototype and the benefits that come with it, makes testing harder and is a huge pain to clone.

var createClass=function(privateInstanceVal){
   var privateMethod=function(val){
     privateInstanceVal.push(val);
     return privateInstanceVal;
   };
   return{
     publicInstanceVar:[],
     publicMethod:function(val){return privateMethod(val);}
   }
};
c1=createClass([]);
var b = c1.publicMethod(33);
console.log("b is:",b);
b.push("because I returned the private I made it public");
console.log(c1.publicMethod(0));//=[33, "because ... public", 0]

The sample shows a mistake sometimes made by returning "private" you made it public. Instead you can return a copy: return privateInstanceVal.concat([]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.