JavaScript private methods

JavaScript private methods

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 can be called by the buy_food and use_restroom methods but not externally by users of the class?
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 these 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.

Solutions/Answers:

Solution 1:

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();
    }
}

Solution 2:

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

Solution 3:

Using self invoking function and call

JavaScript uses prototypes and does’t have classes (or methods for that matter) like Object Oriented languages. A JavaScript developer need to think in JavaScript.

Wikipedia quote:

Unlike many object-oriented languages, there is no distinction between
a function definition and a method definition. Rather, the distinction
occurs during function calling; when a function is called as a method
of an object, the function’s local this keyword is bound to that
object for that invocation.

Solution using a self invoking function and the call function to call the private “method” :

var MyObject = (function () {

    // Constructor
    function MyObject (foo) {
        this._foo = foo;
    }

    function privateFun (prefix) {
        return prefix + this._foo;
    }

    MyObject.prototype.publicFun = function () {
        return privateFun.call(this, '>>');
    }

    return MyObject;
})();


var myObject = new MyObject('bar');
myObject.publicFun();      // Returns '>>bar'
myObject.privateFun('>>'); // ReferenceError: private is not defined

The call function allows us to call the private function with the appropriate context (this).

Simpler with Node.js

If you are using node.js, you don’t need the IIFE because you can take advantage of the module loading system:

function MyObject (foo) {
    this._foo = foo;
}

function privateFun (prefix) {
    return prefix + this._foo;
}

MyObject.prototype.publicFun = function () {
    return privateFun.call(this, '>>');
}

exports.MyObject = MyObject;

Load the file:

var MyObject = require('./MyObject').MyObject;

var myObject = new MyObject('bar');
myObject.publicFun();      // Returns '>>bar'
myObject.privateFun('>>'); // ReferenceError: private is not defined

(experimental) ES7 with the Bind Operator

The bind operator :: is an ECMAScript proposal and is implemented in Babel (stage 0).

export default class MyObject {
  constructor (foo) {
    this._foo = foo;
  }

  publicFun () {
    return this::privateFun('>>');
  }
}

function privateFun (prefix) {
  return prefix + this._foo;
}

Load the file:

import MyObject from './MyObject';

let myObject = new MyObject('bar');
myObject.publicFun();      // Returns '>>bar'
myObject.privateFun('>>'); // TypeError: myObject.privateFun is not a function

Solution 4:

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

Solution 5:

Here is the class which I created to understand what Douglas Crockford’s has suggested in his site Private Members in JavaScript

function Employee(id, name) { //Constructor
    //Public member variables
    this.id = id;
    this.name = name;
    //Private member variables
    var fName;
    var lName;
    var that = this;
    //By convention, we create a private variable 'that'. This is used to     
    //make the object available to the private methods. 

    //Private function
    function setFName(pfname) {
        fName = pfname;
        alert('setFName called');
    }
    //Privileged function
    this.setLName = function (plName, pfname) {
        lName = plName;  //Has access to private variables
        setFName(pfname); //Has access to private function
        alert('setLName called ' + this.id); //Has access to member variables
    }
    //Another privileged member has access to both member variables and private variables
    //Note access of this.dataOfBirth created by public member setDateOfBirth
    this.toString = function () {
        return 'toString called ' + this.id + ' ' + this.name + ' ' + fName + ' ' + lName + ' ' + this.dataOfBirth; 
    }
}
//Public function has access to member variable and can create on too but does not have access to private variable
Employee.prototype.setDateOfBirth = function (dob) {
    alert('setDateOfBirth called ' + this.id);
    this.dataOfBirth = dob;   //Creates new public member note this is accessed by toString
    //alert(fName); //Does not have access to private member
}
$(document).ready()
{
    var employee = new Employee(5, 'Shyam'); //Create a new object and initialize it with constructor
    employee.setLName('Bhaskar', 'Ram');  //Call privileged function
    employee.setDateOfBirth('1/1/2000');  //Call public function
    employee.id = 9;                     //Set up member value
    //employee.setFName('Ram');  //can not call Private Privileged method
    alert(employee.toString());  //See the changed object

}

Solution 6:

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!'