0

In JavaScript, classes are usually emulated through constructors. However, I'm curious as to how one can create an encapsulated class, i.e. a class that keeps some of it's members private.

The commonly seen way of creating a 'class' is as follows:

function MyClass(parameter) {
    this.value = parameter;
}

MyClass.prototype.myPublicFunction = function() {
    console.log("About to run private function.");
    myPrivateFunction();
};

MyClass.prototype.myPrivateFunction = function() {
    ...
};

As you can see, in this example myPrivateFunction is actually public. One approach I've seen to solve this problem is the following:

function MyClass(parameter) {
    this.value = parameter;

    this.myPublicFunction = function() {
        console.log("About to run private function.");
        myPrivateFunction.call(this);
    }

    function myPrivateFunction() {
        ...
    }
}

This works; myPrivateFunction is inaccessible from the outside. But this approach has a problem - all functions in this 'class' are going to be copied across instances, instead of shared through the prototype. Also using privateFunction.call(this) everywhere isn't awesome.

Same goes for non-function members. How can I define a private instance-member in a class? What is the best and what is the most common approach? Is it acceptable to simply rely on a naming convention (such as beginning private function names with a _)?

Aviv Cohn
  • 15,543
  • 25
  • 68
  • 131
  • 1
    There is basically no way to do this properly in ES5. You can do it with [`WeakMap`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) in ES6 but that would mean you can only support very recent browsers. – James Allardice Jan 30 '15 at 15:05
  • James - Could you post a example with it (an answer?). I am not fully aware of the features in ES6 and got a bit curious about how a WeakMap could be used to deal with this. Guess I am growing rusty =) – Prusse Jan 30 '15 at 15:45
  • 1
    Maybe the following will help, it has a protected instance specific pattern: http://stackoverflow.com/a/21800194/1641941 – HMR Jan 30 '15 at 15:51

1 Answers1

2

You could create a scope to hide you private functions with an auto executing function.

Like:

(function(){
    function myPrivateFunction(arg_a, arg_b) {
        /* ... */
        console.log("From priv. function " + this.value);
    }
    window.MyClass = function(parameter) {
        this.value = parameter;

        this.myPublicFunction = function() {
            console.log("About to run private function.");
            myPrivateFunction.call(this, 'arg_a', 'arg_b');
        }

    }
})();

But then you need to use MyClass only after it is declared since now it is an function expression and not a function statement, but all instances of MyClass will share the same instance of myPrivateFunction. but you will need to use Function.prototype.call (as in myPrivateFunction.call(this, 'arg_a', 'arg_b'); to get the value of this keyword to match your instance. If you do just myPrivateFunction('arg_a, 'arg_b'); the keyword this will point to the global object (window on browsers) or null if 'strict mode' is enabled.

Just a note: In my own code I don't do this but rely on naming conventions like MyClass.prototype._myPrivateFunction = function(){}; when not using some framework.

Prusse
  • 4,287
  • 2
  • 24
  • 29