546

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.

John Slegers
  • 45,213
  • 22
  • 199
  • 169
Wayne Kao
  • 8,125
  • 5
  • 30
  • 25
  • Note for modern readers, this question was asked (and answered) before modern versions of Javascript, (known as ECMAScript (or ES)) was in use. If you're just learning JavaScript, the difference in syntax / lack of a `class` is because this question is old. An experimental feature exists that does allow private methods nowadays, with the use of a `#` as a prefix, but doesn't have 100% support as of 2020-08-19 across all browsers. See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields – Josh Desmond Aug 19 '20 at 18:29
  • See [this answer](https://stackoverflow.com/a/39222779/460084) for a a clean & simple 'class' solution with a private and public interface and support for composition – kofifus Feb 22 '17 at 01:13

34 Answers34

452

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();
    }
}
Luke Garrigan
  • 4,571
  • 1
  • 21
  • 29
17 of 26
  • 27,121
  • 13
  • 66
  • 85
  • 9
    Hiding thins inside the closure will not guarantee privacy on all interpreters. See http://code.google.com/p/google-caja/wiki/EvalBreaksClosureEncapsulation – Mike Samuel Sep 29 '08 at 17:37
  • 55
    @mikesamuel - true, but only when those interpreters have bugs in them :) – Jerod Venema May 15 '10 at 15:26
  • 145
    This is a private method all right, but will tend to use up a lot more memory than an usual prototype method, especially if you are creating a lot of these objects. For every object instance, it creates a separate function bound to the object and not the class. Also, this does not get garbage collected until the object itself is destroyed. – Arindam Feb 06 '12 at 22:37
  • 4
    If you make an object McDonalds() inherit from Restaurant() McDonalds can't override private methods if you declare them in this way. Well, actually you can, but it will not work if some other method calls the private, it will call the original version of the method and you also can't call the parent method. So far I have not found a good way to declare private methods that work well with inheritance. This and the performance implications makes this not a very good design pattern at all. I would recommend doing some kind of prefix to indicate private methods, likestarting with an underline. – Hoffmann Jun 25 '13 at 17:56
  • 77
    Private methods aren't supposed to get overridden - they're private. – 17 of 26 Jun 25 '13 at 18:55
  • 4
    If you want private methods (not private data), then simple declare them outside of the prototype and call them like this: myFoo.apply(this, args). Then you can keep the public api small, while still having private methods that work on your local object. – oligofren Feb 17 '14 at 15:34
  • What about if I have a private function inside another function that has been added to the prototype e.g. `Thing.prototype.public = function() { var private = function() {...}; private(); };` Is this still wasteful of memory? – RTF Mar 08 '14 at 19:16
  • 4
    Please consider using **self invoking function** + **call** as described here: http://stackoverflow.com/a/25172901/1480391 – Yves M. Aug 28 '14 at 10:32
  • `eval("Restaurant = " + Restaurant.toString().replace( /{/, "{ this.eval = function(code) { return eval(code); }; " )); var r = new Restaurant(); r.eval("myPrivateVar = \"I can set this too!\"");` – Fozi Feb 05 '15 at 16:03
  • If you come here in 2019: This is a really bad way. Those functions are not only private, also STATIC. See self invoking function way – Javier S Jun 04 '19 at 15:30
  • @Arindam if you are just using one object, it does not use more memory than other solutions I guess? This is the easiest and most readable solution I think, no need to use "weird" JavaScript stuff like `prototype` or `call`. – baptx Jul 22 '19 at 17:57
  • @MikeSamuel then just do `delete window.eval;` and then it's fine. – Sapphire_Brick Dec 12 '19 at 21:37
  • @Sapphire_Brick That only denies access to `eval` to code that hasn't run yet, and will break code that needs `eval` to function. Modules that have loaded can grab and hold onto `eval`. I wrote that in 2008 though, and modern interpreters no longer do that. – Mike Samuel Dec 13 '19 at 21:20
  • @MikeSamuel Under the assumption that nobody's depending on `eval`, what's the problem? – Sapphire_Brick Dec 15 '19 at 17:18
  • @Sapphire_Brick. I don't accept that assumption. There are [very widely used modules](https://github.com/dougwilson/nodejs-depd/blob/9a789740084d4f07a3a611432435ae4671f722ff/index.js#L397-L417) that use `eval` for meta-programming. – Mike Samuel Dec 20 '19 at 15:30
  • well, they shouldn't be using eval, and It's a good thing we aren't talking about metaprogramming. Besides, we can put the `delete window.eval` statement towards the bottom of the code, so you can still do your evil metaprogramming on the top of the code, and have encapsulation on the bottom. – Sapphire_Brick Dec 21 '19 at 23:48
  • Almost... **1)** You still cannot have two instances with their own copies of `myPrivateVar`. **2)** Public methods should be allowed to access `myPrivateVar`. In this implementation you can only access private data from private methods. – CodingYoshi Mar 25 '20 at 21:57
  • @CodingYoshi Both yoshi said we're all incorrect. 1> It does create its own copy of `myPrivateVar`. 2> You CAN access `myPrivateVar` from a anything inside that constructor. – Hunkoys Sep 28 '21 at 23:53
217

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;
}
Yves M.
  • 29,855
  • 23
  • 108
  • 144
  • 38
    This is the best answer. The benefits of private methods, no junk. – TaylorMac Oct 07 '14 at 06:43
  • 1
    @TaylorMac Except for the `.call` part. – pishpish Feb 10 '16 at 18:10
  • @janje ? What's the problem with `.call` ? btw you can move from ES5 and use the `::` bind operator (think about using [babel](https://babeljs.io/)) – Yves M. Feb 10 '16 at 22:59
  • `f()` is cleaner than `f.call( this )`. And your private code might include object literals or function constructors which use their own `this`. – pishpish Feb 11 '16 at 13:57
  • 1
    @janje Huh? That's the point of the question, there is no private `f()` in javascript (not at the moment). – Yves M. Feb 16 '16 at 23:28
  • 2
    @YvesM. The point of the question is choosing the best pattern that simulates it. – pishpish Feb 17 '16 at 19:07
  • 1
    @changed what is the best compromise to have hidden functions (un-callable from outside), nice sintax (no `.call`) and small memory (no functions on the instance) ? Does that even exist ? – Ciprian Tomoiagă Nov 01 '16 at 15:12
  • @destoryer quote: `And your private code ... which use their own this` is inaccurate. With your statement you mean someone using `this` that does not refer to the instance in a private method? `f.call(this)` is necessary, as if the "private method" doesn't need reference to caller object, a better approach should have been using function. If the your point of consideration is syntax, `this.f()` should be expected instead of `f()` for a private method, but that is not much difference to `f.call(this)` imo, Python is actually doing this all the time, but omitting `.call` ie `a.f() == f(a)` – Valen Dec 16 '18 at 16:16
  • Why did you add the # variant to your answer afterwards when a bunch of people already posted it here before you? Just for more upvotes? Unscrupulous. – Thielicious Jan 21 '21 at 15:09
  • 1
    The private field proposal has merged with https://github.com/tc39/proposal-class-fields and is now stage 4. – wheredidthatnamecomefrom Feb 28 '22 at 16:34
163

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
  • 28,393
  • 13
  • 77
  • 72
  • 7
    I would also suggest Douglas Crockford's site as a resource on private / public methods and members http://javascript.crockford.com/private.html – Jared Sep 11 '08 at 01:30
  • 10
    He mentioned that link in the question. – Gulzar Nazim Sep 11 '08 at 01:31
  • 9
    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 Sep 11 '08 at 01:33
  • 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 Sep 11 '08 at 02:13
  • 6
    This should be the solution and accepted answer because the author is clearly using the prototype property. – Gabriel Llamas Jan 31 '12 at 10:00
  • 1
    What about using call, then the private methods will be able to access private members. private_stuff.call(this) – Anders Mar 27 '12 at 06:55
  • 26
    With the pattern proposed by @georgebrock, *all* private data will be shared among *all* restaurant objects. That is akin to static private variables and functions in class based OOP. I assume that the OP does *not* want this. To illustrate what I mean, I created [a jsFiddle](http://jsfiddle.net/feklee/zRLSh/1/). – feklee Jul 30 '12 at 09:39
  • 4
    @feklee: Public methods are defined as properties of a prototype object which is shared between many instances. Here we do exactly the same with private methods: A single, shared `function` object accessible to all instances. You're right in pointing out that this technique doesn't work for private data, but that's not what the question asks for. – georgebrock Jul 30 '12 at 12:00
  • 2
    @georgebrock: Judging from the answer that the OP accepted, he does want to have private members *per object*, not in the prototype object. The use case he posted also suggests this. The state of the restroom, for example, is normally per restaurant. – feklee Jul 30 '12 at 12:49
  • 1
    Do you need the `constructor:Restaurant` part? When I set a constructor's prototype, I usually do e.g. `Restaurant.prototype = {};`, and it seems to work. I don't see how `Restaurant.prototype = (function () { return {}; })();` would be different. – Paul D. Waite Jul 03 '13 at 14:28
  • How would that work with inheritance? You can’t set `Restaurant.prototype` to `Object.create(House.prototype)` for example, since it’s already set. – Evi1M4chine Jul 30 '13 at 15:27
  • 1
    @PaulD.Waite: good question. In this example the constructor is an empty function, but what when this is not the case? It seems that leaving out the `constructor: Restaurant` part doesn't prevent the constructor property to be correctly associated with the Restaurant function. Shouldn't it be `undefined`? – Nicolas Le Thierry d'Ennequin Apr 10 '14 at 10:07
  • 1
    With this approach, the "private" methods cannot be invoked from within the constructor. It looks like a major limitation to me. – Nicolas Le Thierry d'Ennequin Apr 10 '14 at 10:38
  • 1
    @feklee i [updated your fiddle](http://jsfiddle.net/zRLSh/28/) to show how to use a member property instead of inside the prototype. – Tom Kay May 28 '15 at 10:00
  • @NicolasLeThierryd'Ennequin To gain access to private methods in the constructor you could define the public constructor of the prototype explicitly and call it from the real constructor: `function Restaurant() { this.constructor(); }` and `constructor: function(){ private_stuff(); }` – pishpish Feb 10 '16 at 18:05
38

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
  • this kind of thing wouldn't be detected by the autocomplete of an IDE :( – Ali Jun 09 '11 at 02:33
  • 21
    But this is not a class, so you can't have 2 "instances" of this with different states. – DevAntoine Aug 21 '12 at 15:26
  • remove the () part and you have a "class". at least where you can instantiate different isntances with different states. the module pattern is quite memory intensive, though ... – oligofren Feb 17 '14 at 15:56
  • @DevAntoine Look at the comments for 17 of 26's answer. In JavaScript extensible classes and private methods don't easily go hand in hand. My suggestion in this case would be to go with composition over inheritance. Create an extensible prototype with the same methods as the enclosed concrete object. Then internal to your prototype you can decide when to call methods on your concrete object. –  Feb 17 '14 at 17:21
  • Is there any downside to calling the public variables from the private functions like so: `aPrivateMethod = function() { MYLIB.aPublicProperty}`? – Hanna Feb 05 '15 at 22:50
  • This doesn't allow private methods to access public methods. – Stas Bichenko Feb 28 '15 at 15:49
24

ES12 Private Methods

You can do this now with es12 private methods. You just need to add a # before the method name.

class ClassWithPrivateMethod {
  #privateMethod() {
    return 'hello world';
  }

  getPrivateMessage() {
    return #privateMethod();
  }
}
D-Marc
  • 2,937
  • 5
  • 20
  • 28
21

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

}
Lorenzo Polidori
  • 10,332
  • 10
  • 51
  • 60
Sarath
  • 2,719
  • 1
  • 31
  • 39
  • 5
    The that=this is a pattern that is quite common, popularized by aforementioned Crockford in his book "Javascript: The good parts" – oligofren Oct 02 '12 at 16:30
  • 8
    `that` is used instead of `this` to avoid scoping issues, when functions are bound to a different object. Here, you are storing `this` in `that` and never using it again which is the same as not doing it at all. You should change `this` with `that` all across the `Constructor` inner functions (not methods declaration). If `employee` is `apply`ed or `call`ed in some way these methods might throw since `this` will be incorrectly bound. – Maroshii Jul 25 '13 at 22:57
  • Also, every instance will have a full copy of the private functions, inefficient. That on top of the fact that public methods can't access private class vars, makes me want to switch to dart. Unfortunately angulardart is super beta. – Ray Foss May 27 '14 at 05:13
14

ES2021 / ES12 - Private Methods

Private method names start with a hash # prefix and can be accessed only inside the class where it is defined.

class Restaurant {

  // private method
  #private_stuff() {
    console.log("private stuff");
  }

  // public method
  buy_food() {
    this.#private_stuff();
  }

};

const restaurant = new Restaurant();
restaurant.buy_food(); // "private stuff";
restaurant.private_stuff(); // Uncaught TypeError: restaurant.private_stuff is not a function
t_dom93
  • 10,226
  • 1
  • 52
  • 38
  • 1
    Is the `#` on the call site required? It seems rather cumbersome to have to go through all the code and add the `#` at all call sites. – wilx May 18 '21 at 00:45
  • 1
    @wilx You could just press F2 (in VSCode for example) to change the field name, prefix it with #, and the name will be updated everywhere in your code. – Parziphal May 26 '21 at 15:24
  • This has been released, but it's a pity _private class methods_ don't work on Safari & IE atm. [Broswer compatibility list](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields) – Mahsa2 Jul 28 '21 at 14:53
  • Adding `#` will allow calling the private method. `restaurant.#private_stuff(); // "private stuff";` – MIA Mar 15 '23 at 09:34
13

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!'
  • 1
    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 Jun 02 '10 at 16:43
  • 1
    Figured it out, can have `var Car = function(speed) { this.speed = speed; }` and ` return { constructor: Car, ...` – Jason Jun 02 '10 at 19:23
11

I think such questions come up again and again because of the lack of understanding of the closures. Сlosures is most important thing in JS. Every JS programmer have to feel the essence of it.

1. First of all we need to make separate scope (closure).

function () {

}

2. In this area, we can do whatever we want. And no one will know about it.

function () {
    var name,
        secretSkills = {
            pizza: function () { return new Pizza() },
            sushi: function () { return new Sushi() }
        }

    function Restaurant(_name) {
        name = _name
    }
    Restaurant.prototype.getFood = function (name) {
        return name in secretSkills ? secretSkills[name]() : null
    }
}

3. For the world to know about our restaurant class, we have to return it from the closure.

var Restaurant = (function () {
    // Restaurant definition
    return Restaurant
})()

4. At the end, we have:

var Restaurant = (function () {
    var name,
        secretSkills = {
            pizza: function () { return new Pizza() },
            sushi: function () { return new Sushi() }
        }

    function Restaurant(_name) {
        name = _name
    }
    Restaurant.prototype.getFood = function (name) {
        return name in secretSkills ? secretSkills[name]() : null
    }
    return Restaurant
})()

5. Also, this approach has potential for inheritance and templating

// Abstract class
function AbstractRestaurant(skills) {
    var name
    function Restaurant(_name) {
        name = _name
    }
    Restaurant.prototype.getFood = function (name) {
        return skills && name in skills ? skills[name]() : null
    }
    return Restaurant
}

// Concrete classes
SushiRestaurant = AbstractRestaurant({ 
    sushi: function() { return new Sushi() } 
})

PizzaRestaurant = AbstractRestaurant({ 
    pizza: function() { return new Pizza() } 
})

var r1 = new SushiRestaurant('Yo! Sushi'),
    r2 = new PizzaRestaurant('Dominos Pizza')

r1.getFood('sushi')
r2.getFood('pizza')

I hope this helps someone better understand this subject

iimos
  • 4,767
  • 2
  • 33
  • 35
  • 2
    What you have in point 4. is marvellous! I think it's the only answer from all the ones here where you get both the performance/memory gains of using methods on the prototype AND these public methods have full access to the private members. +1 – Hudon Oct 08 '13 at 17:18
  • 7
    It doesn't work. The name variable here acts like static variable and is shared by all instances of Restaurant. Here's jsbin: http://jsbin.com/oqewUWa/2/edit?js,output – Shital Shah Nov 06 '13 at 06:24
  • it's a good try, but as Shital pointed out, the name variable is buggy. – oligofren Feb 17 '14 at 16:00
  • 2
    adding my 2c here to reaffirm this does not work, looks nice, but as pointed out above "name" will serve as a static variable i.e. shared across all instances – Paul Carroll Sep 18 '14 at 22:47
10

Personally, I prefer the following pattern for creating classes in JavaScript :

var myClass = (function() {
    // Private class properties go here

    var blueprint = function() {
        // Private instance properties go here
        ...
    };

    blueprint.prototype = { 
        // Public class properties go here
        ...
    };

    return  {
         // Public class properties go here
        create : function() { return new blueprint(); }
        ...
    };
})();

As you can see, it allows you to define both class properties and instance properties, each of which can be public and private.


Demo

var Restaurant = function() {
    var totalfoodcount = 0;        // Private class property
    var totalrestroomcount  = 0;   // Private class property
    
    var Restaurant = function(name){
        var foodcount = 0;         // Private instance property
        var restroomcount  = 0;    // Private instance property
        
        this.name = name
        
        this.incrementFoodCount = function() {
            foodcount++;
            totalfoodcount++;
            this.printStatus();
        };
        this.incrementRestroomCount = function() {
            restroomcount++;
            totalrestroomcount++;
            this.printStatus();
        };
        this.getRestroomCount = function() {
            return restroomcount;
        },
        this.getFoodCount = function() {
            return foodcount;
        }
    };
   
    Restaurant.prototype = {
        name : '',
        buy_food : function(){
           this.incrementFoodCount();
        },
        use_restroom : function(){
           this.incrementRestroomCount();
        },
        getTotalRestroomCount : function() {
            return totalrestroomcount;
        },
        getTotalFoodCount : function() {
            return totalfoodcount;
        },
        printStatus : function() {
           document.body.innerHTML
               += '<h3>Buying food at '+this.name+'</h3>'
               + '<ul>' 
               + '<li>Restroom count at ' + this.name + ' : '+ this.getRestroomCount() + '</li>'
               + '<li>Food count at ' + this.name + ' : ' + this.getFoodCount() + '</li>'
               + '<li>Total restroom count : '+ this.getTotalRestroomCount() + '</li>'
               + '<li>Total food count : '+ this.getTotalFoodCount() + '</li>'
               + '</ul>';
        }
    };

    return  { // Singleton public properties
        create : function(name) {
            return new Restaurant(name);
        },
        printStatus : function() {
          document.body.innerHTML
              += '<hr />'
              + '<h3>Overview</h3>'
              + '<ul>' 
              + '<li>Total restroom count : '+ Restaurant.prototype.getTotalRestroomCount() + '</li>'
              + '<li>Total food count : '+ Restaurant.prototype.getTotalFoodCount() + '</li>'
              + '</ul>'
              + '<hr />';
        }
    };
}();

var Wendys = Restaurant.create("Wendy's");
var McDonalds = Restaurant.create("McDonald's");
var KFC = Restaurant.create("KFC");
var BurgerKing = Restaurant.create("Burger King");

Restaurant.printStatus();

Wendys.buy_food();
Wendys.use_restroom();
KFC.use_restroom();
KFC.use_restroom();
Wendys.use_restroom();
McDonalds.buy_food();
BurgerKing.buy_food();

Restaurant.printStatus();

BurgerKing.buy_food();
Wendys.use_restroom();
McDonalds.buy_food();
KFC.buy_food();
Wendys.buy_food();
BurgerKing.buy_food();
McDonalds.buy_food();

Restaurant.printStatus();

See also this Fiddle.

Community
  • 1
  • 1
John Slegers
  • 45,213
  • 22
  • 199
  • 169
9

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
  • 99
  • 1
  • 18
    That 9% that are still using IE6 don't care about speed, optimizations and all modern HTML5 features. So closures won't cost anything. – Gabriel Llamas Jan 31 '12 at 10:06
  • 6
    It is now 0.5% (August 2012) http://www.w3schools.com/browsers/browsers_explorer.asp – Lorenzo Polidori Oct 05 '12 at 14:24
  • 7
    @LorenzoPolidori w3schools users !== corporate web users ;] – WynandB Feb 19 '14 at 00:58
  • A naming convention (ex: prepending an underscore) is the way to go. The code is easier to maintain and the methods are still defined on prototype. Nowadays though... I just mark the method as private in typescript. – David Sherret Feb 10 '15 at 18:39
5

Don't be so verbose. It's Javascript. Use a Naming Convention.

After years of working in es6 classes, I recently started work on an es5 project (using requireJS which is already very verbose-looking). I've been over and over all the strategies mentioned here and it all basically boils down to use a naming convention:

  1. Javascript doesn't have scope keywords like private. Other developers entering Javascript will know this upfront. Therefore, a simple naming convention is more than sufficient. A simple naming convention of prefixing with an underscore solves the problem of both private properties and private methods.
  2. Let's take advantage of the Prototype for speed reasons, but lets not get anymore verbose than that. Let's try to keep the es5 "class" looking as closely to what we might expect in other backend languages (and treat every file as a class, even if we don't need to return an instance).
  3. Let's demonstrate with a more realistic module situation (we'll use old es5 and old requireJs).

my-tooltip.js

    define([
        'tooltip'
    ],
    function(
        tooltip
    ){

        function MyTooltip() {
            // Later, if needed, we can remove the underscore on some
            // of these (make public) and allow clients of our class
            // to set them.
            this._selector = "#my-tooltip"
            this._template = 'Hello from inside my tooltip!';
            this._initTooltip();
        }

        MyTooltip.prototype = {
            constructor: MyTooltip,

            _initTooltip: function () {
                new tooltip.tooltip(this._selector, {
                    content: this._template,
                    closeOnClick: true,
                    closeButton: true
                });
            }
        }

        return {
            init: function init() {
               new MyTooltip();  // <-- Our constructor adds our tooltip to the DOM so not much we need to do after instantiation.
            }

            // You could instead return a new instantiation, 
            // if later you do more with this class.
            /* 
            create: function create() {
               return new MyTooltip();
            }
            */
        }
    });
prograhammer
  • 20,132
  • 13
  • 91
  • 118
  • 2
    It should be noted that neither the Javascript language nor any typical browser host defines any objects which rely on naming conventions to "hide" private state, so while you might be right that developers will grasp the concept, it still leads to a very non-OO approach to OO programming. – rich remer Nov 08 '18 at 21:32
  • May I ask for a good reference in making such? There are parts on this example that are new to me. The `define` , and `constructor` and the structure itself. While I agree mostly on the answer, I have started working with JS with a lot of OOP influence and even jumped too early to TS since I had prior experience to C#. I think I have to unlearn these stuff and have to understand the prototyping/procedural paradigm. (upvoted, btw) – Alex Pappas Aug 02 '19 at 06:43
  • 1
    @ColdCerberus this code snippet is using es5. You can see a complete picture of this approach here: https://gist.github.com/jonnyreeves/2474026. But keep in mind, you'll want to take this approach and update it to using es6 classes: https://googlechrome.github.io/samples/classes-es6/ and es6 modules (import/export syntax): https://hackernoon.com/import-export-default-require-commandjs-javascript-nodejs-es6-vs-cheatsheet-different-tutorial-example-5a321738b50f – prograhammer Aug 03 '19 at 16:24
4

Take any of the solutions that follow Crockford's private or priviledged pattern. For example:

function Foo(x) {
    var y = 5;
    var bar = function() {
        return y * x;
    };

    this.public = function(z) {
        return bar() + x * z;
    };
}

In any case where the attacker has no "execute" right on the JS context he has no way of accessing any "public" or "private" fields or methods. In case the attacker does have that access he can execute this one-liner:

eval("Foo = " + Foo.toString().replace(
    /{/, "{ this.eval = function(code) { return eval(code); }; "
));

Note that the above code is generic to all constructor-type-privacy. It will fail with some of the solutions here but it should be clear that pretty much all of the closure based solutions can be broken like this with different replace() parameters.

After this is executed any object created with new Foo() is going to have an eval method which can be called to return or change values or methods defined in the constructor's closure, e.g.:

f = new Foo(99);
f.eval("x");
f.eval("y");
f.eval("x = 8");

The only problem I can see with this that it won't work for cases where there is only one instance and it's created on load. But then there is no reason to actually define a prototype and in that case the attacker can simply recreate the object instead of the constructor as long as he has a way of passing the same parameters (e.g. they are constant or calculated from available values).

In my opinion, this pretty much makes Crockford's solution useless. Since the "privacy" is easily broken the downsides of his solution (reduced readability & maintainability, decreased performance, increased memory) makes the "no privacy" prototype based method the better choice.

I do usually use leading underscores to mark __private and _protected methods and fields (Perl style), but the idea of having privacy in JavaScript just shows how it's a misunderstood language.

Therefore I disagree with Crockford except for his first sentence.

So how do you get real privacy in JS? Put everything that is required to be private on the server side and use JS to do AJAX calls.

Fozi
  • 4,973
  • 1
  • 32
  • 56
  • This is a serious issue which should be more well known. Is there a 'defence' against this attack? – James Feb 03 '15 at 10:06
  • @James None that I know of, I think it's the nature of the beast. As I pointed out you can move functionality to the server where it runs in a protected environment. The point I wanted to get over in my answer though is that Crockford's solution is not helping, unnecessarily complicates code and hides the necessity to do something about it. – Fozi Feb 03 '15 at 19:08
  • If a user entersa secret password, he can't do this server-side. At some point the password will be in a 'private' var. So could an attacker read it? I trust my code, and anyway my house standards do not permit eval(). The attacker could be some malicious third party JavaScript plug-in or library that I didn't check properly - so, yes I need to check these. The attacker might also be something like an advert on the side that should not interact with my code. I protect against that by wrapping all my code in an anonymous `(function () {allMyStuff}());` so as to expose nothing global. – James Feb 04 '15 at 11:20
  • @James This is getting OT, if you want to continue this please open a new question. Yes, an attacker can read the password. From your "private" variable. Or from the DOM. Or he can replace the AJAX API. Or he replaces your page with something else. If he can't do any of the above then there is no need for JS "privacy" because he can't read any of your JS variables either. The point is that Crockford's "solution" that everyone is using right now is not helping with this problem. – Fozi Feb 04 '15 at 15:15
  • I believe pseudorandom code obfuscation may be a weak defense against this attack - more difficult to modify function body when you can't depend on the function having a fixed name; more difficult to do `f.eval('nameOfVariable')` when you don't know what `'nameOfVariable'` is... – Gershom Maes Feb 26 '20 at 16:44
  • a possible workaround is to just initially define the constructor as a read-only property of window so it cannot be redeclared: `Object.defineProperty(window, "MyClass", { get: () => function() { let _privateMethod = () => "somethingSecret"; } })` – B''H Bi'ezras -- Boruch Hashem Apr 14 '20 at 06:27
  • @bluejayke I can still get your secret: `eval("MyEvilClass = " + MyClass.toString().replace( /{/, "{ this.eval = function(code) { return eval(code); }; " ));` `inst = new MyEvilClass();` `inst.eval("_privateMethod()");` returns `"somethingSecret"`. It's pointless, it's just a game of walls and ladders. At one point your code is so obfuscated, unreadable, slow and such a memory hog that you might as well write a Java applet instead. – Fozi Apr 15 '20 at 02:07
2

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
  • 5,042
  • 1
  • 19
  • 11
2

What about this?

var Restaurant = (function() {

 var _id = 0;
 var privateVars = [];

 function Restaurant(name) {
     this.id = ++_id;
     this.name = name;
     privateVars[this.id] = {
         cooked: []
     };
 }

 Restaurant.prototype.cook = function (food) {
     privateVars[this.id].cooked.push(food);
 }

 return Restaurant;

})();

Private variable lookup is impossible outside of the scope of the immediate function. There is no duplication of functions, saving memory.

The downside is that the lookup of private variables is clunky privateVars[this.id].cooked is ridiculous to type. There is also an extra "id" variable.

Yves M.
  • 29,855
  • 23
  • 108
  • 144
Evan Leis
  • 494
  • 5
  • 13
  • This will leave `Restaurant` as `undefined` because you're not returning anything from the anonymous function. – user4815162342 Feb 05 '14 at 10:13
  • Where and how? Assuming the reference to the created Restaurant is lost, privateVars won't have a reference to its owner. The reference graph is acyclic. What am I missing? – Evan Leis Aug 12 '14 at 19:50
  • Actually this is the only answer that supports private properties besides methods. The only two issues are already noted in the answer. – pishpish Feb 10 '16 at 18:22
  • I see a memory leak: when an instance of `Restaurant` has been garbage-collected, its values remain within `privateVars`. A `WeakMap` may be a good replacement for the `Array` in this case. – Gershom Maes Feb 26 '20 at 16:37
2

Here's what i enjoyed the most so far regarding private/public methods/members and instantiation in javascript:

here is the article: http://www.sefol.com/?p=1090

and here is the example:

var Person = (function () {

    //Immediately returns an anonymous function which builds our modules 
    return function (name, location) {

        alert("createPerson called with " + name);

        var localPrivateVar = name;

        var localPublicVar = "A public variable";

        var localPublicFunction = function () {
            alert("PUBLIC Func called, private var is :" + localPrivateVar)
        };

        var localPrivateFunction = function () {
            alert("PRIVATE Func called ")
        };

        var setName = function (name) {

            localPrivateVar = name;

        }

        return {

            publicVar: localPublicVar,

            location: location,

            publicFunction: localPublicFunction,

            setName: setName

        }

    }
})();


//Request a Person instance - should print "createPerson called with ben"
var x = Person("ben", "germany");

//Request a Person instance - should print "createPerson called with candide"
var y = Person("candide", "belgium");

//Prints "ben"
x.publicFunction();

//Prints "candide"
y.publicFunction();

//Now call a public function which sets the value of a private variable in the x instance
x.setName("Ben 2");

//Shouldn't have changed this : prints "candide"
y.publicFunction();

//Should have changed this : prints "Ben 2"
x.publicFunction();

JSFiddle: http://jsfiddle.net/northkildonan/kopj3dt3/1/

low_rents
  • 4,481
  • 3
  • 27
  • 55
  • this approach has one important consern - if you've created 2 objects, in memory there will be 2 same methds (PublicFunction for e.g.) 1000 objects will eat all your memory. – Artem A Jun 22 '15 at 11:44
2

The module pattern is right in most cases. But if you have thousands of instances, classes save memory. If saving memory is a concern and your objects contain a small amount of private data, but have a lot of public functions, then you'll want all public functions to live in the .prototype to save memory.

This is what I came up with:

var MyClass = (function () {
    var secret = {}; // You can only getPriv() if you know this
    function MyClass() {
        var that = this, priv = {
            foo: 0 // ... and other private values
        };
        that.getPriv = function (proof) {
            return (proof === secret) && priv;
        };
    }
    MyClass.prototype.inc = function () {
        var priv = this.getPriv(secret);
        priv.foo += 1;
        return priv.foo;
    };
    return MyClass;
}());
var x = new MyClass();
x.inc(); // 1
x.inc(); // 2

The object priv contains private properties. It is accessible through the public function getPriv(), but this function returns false unless you pass it the secret, and this is only known inside the main closure.

James
  • 5,635
  • 2
  • 33
  • 44
  • That simulates protected members, types inheriting from it can access the protected members as well. I favor this pattern over the private one as well – HMR Feb 03 '15 at 00:04
2

Wrap all code in Anonymous Function: Then , all functions will be private ,ONLY functions attached to window object :

(function(w,nameSpacePrivate){
     w.Person=function(name){
         this.name=name;   
         return this;
     };

     w.Person.prototype.profilePublic=function(){
          return nameSpacePrivate.profile.call(this);
     };  

     nameSpacePrivate.profile=function(){
       return 'My name is '+this.name;
     };

})(window,{});

Use this :

  var abdennour=new Person('Abdennour');
  abdennour.profilePublic();

FIDDLE

Abdennour TOUMI
  • 87,526
  • 38
  • 249
  • 254
2

The apotheosis of the Module Pattern: The Revealing Module Pattern

A neat little extension to a very robust pattern.

2
var TestClass = function( ) {

    var privateProperty = 42;

    function privateMethod( ) {
        alert( "privateMethod, " + privateProperty );
    }

    this.public = {
        constructor: TestClass,

        publicProperty: 88,
        publicMethod: function( ) {
            alert( "publicMethod" );
            privateMethod( );
        }
    };
};
TestClass.prototype = new TestClass( ).public;


var myTestClass = new TestClass( );

alert( myTestClass.publicProperty );
myTestClass.publicMethod( );

alert( myTestClass.privateMethod || "no privateMethod" );

Similar to georgebrock but a little less verbose (IMHO) Any problems with doing it this way? (I haven't seen it anywhere)

edit: I realised this is kinda useless since every independent instantiation has its own copy of the public methods, thus undermining the use of the prototype.

forsvarir
  • 10,749
  • 6
  • 46
  • 77
David
  • 21
  • 2
1

I prefer to store private data in an associated WeakMap. This allows you to keep your public methods on the prototype where they belong. This seems to be the most efficient way to handle this problem for large numbers of objects.

const data = new WeakMap();

function Foo(value) {
    data.set(this, {value});
}

// public method accessing private value
Foo.prototype.accessValue = function() {
    return data.get(this).value;
}

// private 'method' accessing private value
function accessValue(foo) {
    return data.get(foo).value;
}

export {Foo};
rich remer
  • 3,407
  • 2
  • 34
  • 47
1

2021 HERE!

This polyfill effectively hides your private properties and methods returning undefined when you try to read your private property and a TypeError when you try to execute your private method thus effectively making them both PRIVATE to the outside but giving you access to them by using your public methods.

If you check it you will see it is very easy to implement. For the most part you don't need to do anything quirky like using Proxy objects, underscore functions (_myprivate), getters or setters. None of that. The only thing required is to place in your constructor that like snippet of code that is aimed to let you expose your public interface to the outside world.

((self) => ({
      pubProp: self.pubProp,
      // More public properties to export HERE
      // ...
      pubMethod: self.pubMethod.bind(self)
      // More public mehods to export HERE
      // Be sure bind each of them to self!!!
      // ... 
 }))(self);

The above code is where the magic happens. It is an IIFE that returns an object with just the properties and methods you want to exposed and bound to the context of the object that was first instantiated.

You can still access your hidden properties and methods but only through your public methods just the way OOP should do.
Consider that part of the code as your module.exports

BTW, this is without using the latest ECMAScript 2022 # addition to the language.

'use strict';

class MyClass {
  constructor(pubProp) {
    let self = this;
    self.pubProp = pubProp;
    self.privProp = "I'm a private property!";
    return ((self) => ({
      pubProp: self.pubProp,
      // More public properties to export HERE
      // ...
      pubMethod: self.pubMethod.bind(self)
      // More public mehods to export HERE
      // Be sure to bind each of them to self!!!
      // ... 
    }))(self);
  }

  pubMethod() {
    console.log("I'm a public method!");
    console.log(this.pubProp);

    return this.privMethod();
  }

  privMethod() {
    console.log("I'm a private method!");
  return this.privProp
  }
}

const myObj = new MyClass("I'm a public property!");
console.log("***DUMPING MY NEW INSTANCE***");
console.dir(myObj);
console.log("");
console.log("***TESTING ACCESS TO PUBLIC PROPERTIES***");
console.log(myObj.pubProp);
console.log("");
console.log("***TESTING ACCESS TO PRIVATE PROPERTIES***");
console.log(myObj.privProp);
console.log("");
console.log("***TESTING ACCESS TO PUBLIC METHODS***");
console.log("1. pubMethod access pubProp ");
console.log("2. pubMethod calls privMethod");
console.log("3. privMethod access privProp");
console.log("")
console.log(myObj.pubMethod());
console.log("");
console.log("***TESTING ACCESS TO PRIVATE METHODS***");
console.log(myObj.privMethod());

Check my gist

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
denik1981
  • 370
  • 2
  • 12
0

Since everybody was posting here his own code, I'm gonna do that too...

I like Crockford because he introduced real object oriented patterns in Javascript. But he also came up with a new misunderstanding, the "that" one.

So why is he using "that = this"? It has nothing to do with private functions at all. It has to do with inner functions!

Because according to Crockford this is buggy code:

Function Foo( ) {
    this.bar = 0; 
    var foobar=function( ) {
        alert(this.bar);
    }
} 

So he suggested doing this:

Function Foo( ) {
    this.bar = 0;
    that = this; 
    var foobar=function( ) {
        alert(that.bar);
    }
}

So as I said, I'm quite sure that Crockford was wrong his explanation about that and this (but his code is certainly correct). Or was he just fooling the Javascript world, to know who is copying his code? I dunno...I'm no browser geek ;D

EDIT

Ah, that's what is all about: What does 'var that = this;' mean in JavaScript?

So Crockie was really wrong with his explanation....but right with his code, so he's still a great guy. :))

Community
  • 1
  • 1
mark
  • 84
  • 1
  • 2
0

In general I added the private Object _ temporarily to the object. You have to open the privacy exlipcitly in the "Power-constructor" for the method. If you call the method from the prototype, you will be able to overwrite the prototype-method

  • Make a public method accessible in the "Power-constructor": (ctx is the object context)

    ctx.test = GD.Fabric.open('test', GD.Test.prototype, ctx, _); // is a private object
    
  • Now I have this openPrivacy:

    GD.Fabric.openPrivacy = function(func, clss, ctx, _) {
        return function() {
            ctx._ = _;
            var res = clss[func].apply(ctx, arguments);
            ctx._ = null;
            return res;
        };
    };
    
Andreas Dyballa
  • 179
  • 1
  • 5
0

You have to put a closure around your actual constructor-function, where you can define your private methods. To change data of the instances through these private methods, you have to give them "this" with them, either as an function argument or by calling this function with .apply(this) :

var Restaurant = (function(){
    var private_buy_food = function(that){
        that.data.soldFood = true;
    }
    var private_take_a_shit = function(){
        this.data.isdirty = true;   
    }
    // New Closure
    function restaurant()
    {
        this.data = {
            isdirty : false,
            soldFood: false,
        };
    }

    restaurant.prototype.buy_food = function()
    {
       private_buy_food(this);
    }
    restaurant.prototype.use_restroom = function()
    {
       private_take_a_shit.call(this);
    }
    return restaurant;
})()

// TEST:

var McDonalds = new Restaurant();
McDonalds.buy_food();
McDonalds.use_restroom();
console.log(McDonalds);
console.log(McDonalds.__proto__);
Flex Elektro Deimling
  • 1,599
  • 1
  • 17
  • 16
  • Actually, it doesn't work. Every `new Restaurant` will have its own `restaurant` contstructor, and the "prototype" is totally abused. – Bergi Aug 07 '14 at 02:05
  • @Bergi. Actually, you´re right. It would work but would also be a ressource hog (is it called like that?). I edited my answer in regard of that. – Flex Elektro Deimling Aug 09 '14 at 14:40
  • Thanks for the update. No idea what to call the previous version (but "bug" :-) – Bergi Aug 09 '14 at 14:43
0

This is what I worked out:

Needs one class of sugar code that you can find here. Also supports protected, inheritance, virtual, static stuff...

;( function class_Restaurant( namespace )
{
    'use strict';

    if( namespace[ "Restaurant" ] ) return    // protect against double inclusions

        namespace.Restaurant = Restaurant
    var Static               = TidBits.OoJs.setupClass( namespace, "Restaurant" )


    // constructor
    //
    function Restaurant()
    {
        this.toilets = 3

        this.Private( private_stuff )

        return this.Public( buy_food, use_restroom )
    }

    function private_stuff(){ console.log( "There are", this.toilets, "toilets available") }

    function buy_food     (){ return "food"        }
    function use_restroom (){ this.private_stuff() }

})( window )


var chinese = new Restaurant

console.log( chinese.buy_food()      );  // output: food
console.log( chinese.use_restroom()  );  // output: There are 3 toilets available
console.log( chinese.toilets         );  // output: undefined
console.log( chinese.private_stuff() );  // output: undefined

// and throws: TypeError: Object #<Restaurant> has no method 'private_stuff'
0
Class({  
    Namespace:ABC,  
    Name:"ClassL2",  
    Bases:[ABC.ClassTop],  
    Private:{  
        m_var:2  
    },  
    Protected:{  
        proval:2,  
        fight:Property(function(){  
            this.m_var--;  
            console.log("ClassL2::fight (m_var)" +this.m_var);  
        },[Property.Type.Virtual])  
    },  
    Public:{  
        Fight:function(){  
            console.log("ClassL2::Fight (m_var)"+this.m_var);  
            this.fight();  
        }  
    }  
});  

https://github.com/nooning/JSClass

0

I have created a new tool to allow you to have true private methods on the prototype https://github.com/TremayneChrist/ProtectJS

Example:

var MyObject = (function () {

  // Create the object
  function MyObject() {}

  // Add methods to the prototype
  MyObject.prototype = {

    // This is our public method
    public: function () {
      console.log('PUBLIC method has been called');
    },

    // This is our private method, using (_)
    _private: function () {
      console.log('PRIVATE method has been called');
    }
  }

  return protect(MyObject);

})();

// Create an instance of the object
var mo = new MyObject();

// Call its methods
mo.public(); // Pass
mo._private(); // Fail
Trem
  • 100
  • 1
  • 3
  • 1
    Can you explain how it works, please? How/where *can* you call the `_private` method? – Bergi Aug 07 '14 at 02:06
0

I know it's a bit too late but how about this?

var obj = function(){
    var pr = "private";
    var prt = Object.getPrototypeOf(this);
    if(!prt.hasOwnProperty("showPrivate")){
        prt.showPrivate = function(){
            console.log(pr);
        }
    }    
}

var i = new obj();
i.showPrivate();
console.log(i.hasOwnProperty("pr"));
Maxim Balaganskiy
  • 1,524
  • 13
  • 25
0

There are many answers on this question already, but nothing fitted my needs. So i came up with my own solution, I hope it is usefull for someone:

function calledPrivate(){
    var stack = new Error().stack.toString().split("\n");
    function getClass(line){
        var i = line.indexOf(" ");
        var i2 = line.indexOf(".");
        return line.substring(i,i2);
    }
    return getClass(stack[2])==getClass(stack[3]);
}

class Obj{
    privateMethode(){
        if(calledPrivate()){
            console.log("your code goes here");
        }
    }
    publicMethode(){
        this.privateMethode();
    }
}

var obj = new Obj();
obj.publicMethode(); //logs "your code goes here"
obj.privateMethode(); //does nothing

As you can see this system works when using this type of classes in javascript. As far as I figured out none of the methods commented above did.

thegunmaster
  • 265
  • 4
  • 14
  • 1
    Curious: Was your need really to actually expose the function but make it a no-op in runtime - rather than hiding it from external callers as all/most other answers do? If so, why? What do you consider to be the benefit of this approach? To me, this seems to be just an unnecessary performance overhead, an unclear API and, well, probably bound to cause debug hell, but I'm always open to new perspectives... – JHH Jan 08 '18 at 13:42
  • 2
    @JHH to be honest, I am pretty much face palming when looking back at this. The overhead is generally not worth it at all, though for me it didn't matter an awful lot as I didn't make many calls to these classes. The reason I did it this way is just that it is relatively clean in the way you write and call the functions. I didn't understand symbols and such by the time, but now that I do, I think that generally is the way to go when using classes. I am considering removing this answer all together. I have posted several stupid answers, but hey, you live and learn. – thegunmaster Feb 19 '18 at 15:38
  • Thanks for the feedback! I wasn't sure if I had misunderstood something. But yes, we all live and learn! – JHH Feb 19 '18 at 16:56
0

Private functions cannot access the public variables using module pattern

Dooma
  • 9
  • 1
0

An ugly solution but it works:

function Class(cb) {
    const self = {};

    const constructor = (fn) => {
        func = fn;    
    };

    const addPrivate = (fnName, obj) => {
        self[fnName] = obj;
    }

    const addPublic = (fnName, obj) => {
        this[fnName] = obj;
        self[fnName] = obj;
        func.prototype[fnName] = obj;
    }
    
    cb(constructor, addPrivate, addPublic, self);
    return func;
}

const test = new Class((constructor, private, public, self) => {
    constructor(function (test) {
        console.log(test)
    });
    public('test', 'yay');
    private('qwe', 'nay');
    private('no', () => {
        return 'hello'
    })
    public('asd', () => {
        return 'this is public'
    })
    public('hello', () => {
        return self.qwe + self.no() + self.asd()
    })
})
const asd = new test('qweqwe');
console.log(asd.hello());
Daniel Shlomo
  • 105
  • 1
  • 2
  • 17
0

Old question but this is a rather simple task that can be solved properly with core JS... without the Class abstraction of ES6. In fact as far as i can tell, the Class abstraction do not even solve this problem.

We can do this job both with the good old constructor function or even better with Object.create(). Lets go with the constructor first. This will essentially be a similar solution to georgebrock's answer which is criticised because all restaurants created by the Restaurant constructor will have the same private methods. I will try to overcome that limitation.

function restaurantFactory(name,menu){

  function Restaurant(name){
    this.name = name;
  }

  function prototypeFactory(menu){
    // This is a private function
    function calculateBill(item){
      return menu[item] || 0;
    }
    // This is the prototype to be
    return { constructor: Restaurant
           , askBill    : function(...items){
                            var cost = items.reduce((total,item) => total + calculateBill(item) ,0)
                            return "Thank you for dining at " + this.name + ". Total is: " + cost + "\n"
                          }
           , callWaiter : function(){
                            return "I have just called the waiter at " + this.name + "\n";
                          }
           }
  }

  Restaurant.prototype = prototypeFactory(menu);

  return new Restaurant(name,menu);
}

var menu = { water: 1
           , coke : 2
           , beer : 3
           , beef : 15
           , rice : 2
           },
    name = "Silver Scooop",
    rest = restaurantFactory(name,menu);

console.log(rest.callWaiter());
console.log(rest.askBill("beer", "beef"));

Now obviously we can not access menu from outside but we may easily rename the name property of a restaurant.

This can also be done with Object.create() in which case we skip the constructor function and simply do like var rest = Object.create(prototypeFactory(menu)) and add the name property to the rest object afterwards like rest.name = name.

Redu
  • 25,060
  • 6
  • 56
  • 76
0

I know it is an old topic but i tried to find a way to preserve the code 'simplicity' for maintainability purposes and keep a light memory load. It came with this pattern. Hope it helps.

const PublicClass=function(priv,pub,ro){
    let _priv=new PrivateClass(priv,pub,ro);
    ['publicMethod'].forEach(k=>this[k]=(...args)=>_priv[k](...args));
    ['publicVar'].forEach(k=>Object.defineProperty(this,k,{get:()=>_priv[k],set:v=>_priv[k]=v}));
    ['readOnlyVar'].forEach(k=>Object.defineProperty(this,k,{get:()=>_priv[k]}));
};

class PrivateClass{
    constructor(priv,pub,ro){
        this.privateVar=priv;
        this.publicVar=pub;
        this.readOnlyVar=ro;
    }
    publicMethod(arg1,arg2){
        return this.privateMethod(arg1,arg2);
    }
    privateMethod(arg1,arg2){
        return arg1+''+arg2;
    }
}
// in node;
module.exports=PublicClass;
// in browser;
const PublicClass=(function(){
    // code here
    return PublicClass;
})();

Same principle for old browsers :

var PublicClass=function(priv,pub,ro){
    var scope=this;
    var _priv=new PrivateClass(priv,pub,ro);
    ['publicMethod'].forEach(function(k){
        scope[k]=function(){return _priv[k].apply(_priv,arguments)};
    });
    ['publicVar'].forEach(function(k){
        Object.defineProperty(scope,k,{get:function(){return _priv[k]},set:function(v){_priv[k]=v}});
    });
    ['readOnlyVar'].forEach(function(k){
        Object.defineProperty(scope,k,{get:function(){return _priv[k]}});
    });
};

var PrivateClass=function(priv,pub,ro){
    this.privateVar=priv;
    this.publicVar=pub;
    this.readOnlyVar=ro;
};
PrivateClass.prototype.publicMethod=function(arg1,arg2){
    return this.privateMethod(arg1,arg2);
};
PrivateClass.prototype.privateMethod=function(arg1,arg2){
    return arg1+''+arg2;
};

To lighten public class verbosity and load, apply this pattern to a constructor :

const AbstractPublicClass=function(instanciate,inherit){
    let _priv=instanciate();
    inherit.methods?.forEach(k=>this[k]=(...args)=>_priv[k](...args));
    inherit.vars?.forEach(k=>Object.defineProperty(this,k,{get:()=>_priv[k],set:v=>_priv[k]=v}));
    inherit.readonly?.forEach(k=>Object.defineProperty(this,k,{get:()=>_priv[k]}));
};

AbstractPublicClass.static=function(_pub,_priv,inherit){
    inherit.methods?.forEach(k=>_pub[k]=(...args)=>_priv[k](...args));
    inherit.vars?.forEach(k=>Object.defineProperty(_pub,k,{get:()=>_priv[k],set:v=>_priv[k]=v}));
    inherit.readonly?.forEach(k=>Object.defineProperty(_pub,k,{get:()=>_priv[k]}));
};

Use :

// PrivateClass ...
PrivateClass.staticVar='zog';
PrivateClass.staticMethod=function(){return 'hello '+this.staticVar;};


const PublicClass=function(priv,pub,ro){
    AbstractPublicClass.apply(this,[()=>new PrivateClass(priv,pub,ro),{
        methods:['publicMethod'],
        vars:['publicVar'],
        readonly:['readOnlyVar']
    }]);
};
AbstractPublicClass.static(PublicClass,PrivateClass,{
    methods:['staticMethod'],
    vars:['staticVar']
});

PS : The default (negligeable most of the time) in this approach is it can take a tiny computing load compared to a full public. But as long as you dont use it whith highly solicited classes that should be ok.

yorg
  • 600
  • 5
  • 7