tags:

views:

5118

answers:

8

To make a JavaScript class with a public method I'd do something like:

function Restaurant()
{
}

Restaurant.prototype.buy_food = function()
{
   // something here
}

Restaurant.prototype.use_restroom = function()
{
   // something here
}

That way users of my class can:

var restaurant = new Restaurant();
restaurant.buy_food();
restaurant.use_restroom();

How do I create a private method that my public buy_food and use_restroom methods can call but that users of the class can't call externally.

In other words, I want my method implementation to be able to do:

Restaurant.prototype.use_restroom = function()
{
   this.private_stuff();
}

But this shouldn't work:

var r = new Restaurant();
r.private_stuff();

How do I define private_stuff as a private method so both of those hold true?

I've read Doug Crockford's writeup a few times but it doesn't seem like "private" methods can be called by public methods and "privileged" methods can be called externally.

+16  A: 

You can do it, but the downside is that it can't be part of the prototype:

function Restaurant()
{
    var myPrivateVar;

    var private_stuff = function()   // Only visible inside Restaurant()
    {
        myPrivateVar = "I can set this here!";
    }

    this.use_restroom = function()   // use_restroom is visible to all
    {
        private_stuff();
    }

    this.buy_food = function()    // buy_food is visible to all
    {
        private_stuff();
    }
}
17 of 26
Hiding thins inside the closure will not guarantee privacy on all interpreters. See http://code.google.com/p/google-caja/wiki/EvalBreaksClosureEncapsulation
Mike Samuel
@mikesamuel - true, but only when those interpreters have bugs in them :)
jvenema
+15  A: 

You can simulate private methods like this:

function Restaurant() 
{
}

Restaurant.prototype = (function()
{
 var private_stuff = function() 
 {
  // Private code here
 };

 return {

  constructor:Restaurant,

  use_restroom:function()
  {
   private_stuff();
  }

 };
})();

var r = new Restaurant();

// This will work:
r.use_restroom();

// This will cause an error:
r.private_stuff();

More information on this technique here: http://webreflection.blogspot.com/2008/04/natural-javascript-private-methods.html

georgebrock
I would also suggest Douglas Crockford's site as a resource on private / public methods and members http://javascript.crockford.com/private.html
Jared
He mentioned that link in the question.
Gulzar
The downside to this method is that you couldn't have private_stuff() access other private data in Restaurant and other Restaurant methods can't call private_stuff().The upside is that if you don't need either of the conditions I just mentioned, you can keep use_restroom() in the prototype.
17 of 26
I also dislike this approach's verbosity so probably wouldn't use it in the general case. It is nifty how it gets added to the prototype though and in JS usually performance wins out against all else.
Wayne Kao
+5  A: 

In these situations when you have a public API, and you would like private and public methods/properties, I always use the Module Pattern. This pattern was made popular within the YUI library, and the details can be found here:

http://yuiblog.com/blog/2007/06/12/module-pattern/

It is really straightforward, and easy for other developers to comprehend. For a simple example:

var MYLIB = function() {  
    var aPrivateProperty = true;
    var aPrivateMethod = function() {
     // some code here...
    };
    return {
     aPublicMethod : function() {
      aPrivateMethod(); // okay
      // some code here...
     },
     aPublicProperty : true
    };  
}();

MYLIB.aPrivateMethod() // not okay
MYLIB.aPublicMethod() // okay
hal10001
+1  A: 

The apotheosis of the Module Pattern: The Revealing Module Pattern

A neat little extension to a very robust pattern.

Daniel Stockman
+1  A: 

All of this closure will cost you. Make sure you test the speed implications especially in IE. You will find you are better off with a naming convention. There are still a lot of corporate web users out there that are forced to use IE6...

Kelly
A: 

If you want the full range of public and private functions with the ability for public functions to access private functions, layout code for an object like this:

function MyObject(arg1, arg2, ...) {
  //constructor code using constructor arguments...
  //create/access public variables as 
  // this.var1 = foo;

  //private variables

  var v1;
  var v2;

  //private functions
  function privateOne() {
  }

  function privateTwon() {
  }

  //public functions

  MyObject.prototype.publicOne = function () {
  };

  MyObject.prototype.publicTwo = function () {
  };
}
domgblackwell
Can someone tell me why this got voted down? Looks good to me.
thomasrutter
+2  A: 

I conjured up this: EDIT: Actually, someone has linked to a identical solution. Duh!

var Car = function() {
}

Car.prototype = (function() {
    var hotWire = function() {
     // Private code *with* access to public properties through 'this'
     alert( this.drive() ); // Alerts 'Vroom!'
    }

    return {
     steal: function() {
      hotWire.call( this ); // Call a private method
     },
     drive: function() {
      return 'Vroom!';
     }
    };
})();

var getAwayVechile = new Car();

hotWire(); // Not allowed
getAwayVechile.hotWire(); // Not allowed
getAwayVechile.steal(); // Alerts 'Vroom!'
Tim
This is a nice technique, but how would you allow parameters in your constructor? For example `var getAwayVehicle = new Car(100);` where `100` is speed and you want to alert speed. Thanks!
Jason
Figured it out, can have `var Car = function(speed) { this.speed = speed; }` and ` return { constructor: Car, ...`
Jason
A: 
function MyObject(arg1, arg2, ...) {
  //constructor code using constructor arguments...
  //create/access public variables as 
  // this.var1 = foo;

  //private variables

  var v1;
  var v2;

  //private functions
  function privateOne() {
  }

  function privateTwon() {
  }

  //public functions

  MyObject.prototype.publicOne = function () {
  };

  MyObject.prototype.publicTwo = function () {
  };
}

Can someone explain what is wrong with the above method of creating private functions while still allowing your public methods to access them. I ommitted using "var" and just defined functions without the var keyword, as opposed to:

var privateOne = function() { };
James