Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 585
Wayne Kao Avatar asked Sep 11 '08 01:09

Wayne Kao


People also ask

Does JavaScript have private methods?

Private methods are defined in JavaScript to hide crucial class methods or keep sensitive information private. In a class, to define a private method instance, private static method, or a private getter and setter, you have to prefix its name with the hash character #.

Does JavaScript have public and private methods?

Class fields are public by default, but private class members can be created by using a hash # prefix. The privacy encapsulation of these class features is enforced by JavaScript itself.

What does private mean in JavaScript?

A private function can only be used inside of it's parent function or module. A public function can be used inside or outside of it. Public functions can call private functions inside them, however, since they typically share the same scope.

How do you make an object private in JavaScript?

The private keyword in object-oriented languages is an access modifier that can be used to make properties and methods only accessible inside the declared class. This makes it easy to hide underlying logic that should be hidden from curious eyes and should not be interacted with outside from the class.


2 Answers

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();     } } 
like image 89
17 of 26 Avatar answered Sep 18 '22 14:09

17 of 26


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, ">>"); }      module.exports= MyObject; 

Load the file:

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

(new!) Native private methods in future JavaScript versions

TC39 private methods and getter/setters for JavaScript classes proposal is stage 3. That means any time soon, JavaScript will implement private methods natively!

Note that JavaScript private class fields already exists in modern JavaScript versions.

Here is an example of how it is used:

class MyObject {    // Private field   #foo;        constructor(foo) {     this.#foo = foo;   }    #privateFun(prefix) {    return prefix + this.#foo;   }        publicFun() {     return this.#privateFun(">>");   }  } 

You may need a JavaScript transpiler/compiler to run this code on old JavaScript engines.

PS: If you wonder why the # prefix, read this.

(deprecated) ES7 with the Bind Operator

Warning: The bind operator TC39 proposition is near dead https://github.com/tc39/proposal-bind-operator/issues/53#issuecomment-374271822

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; } 
like image 37
Yves M. Avatar answered Sep 18 '22 14:09

Yves M.