6

Normally I use standard OOP approach based on prototype and my class looks like this

var std = function(){
   this.log = function(msg){ console.log("want to be private. " + msg) };
};

std.prototype = {
    logInfo: function(msg){
        this.log(msg);
    }
};

but in that case log is public method and anyone could use it. But I want to make it private, but still available in methods declared in prototype. For that we will need closures. Code will change to this

var closureStd = (function(){
var std = function(){};
var log = function(msg){ console.log("I'm really private, youhooo!" + msg) };

std.prototype = {
    logInfo: function(msg){
        log(msg);
    }
};

return std;
})();

So my question: what is the difference between std and closureStd and what is the price I need to pay to be able to call private methods from prototype?

Ph0en1x
  • 9,943
  • 8
  • 48
  • 97
  • 1
    Helpfull links for you: [The cost of privacy](http://blog.jcoglan.com/2012/01/19/the-cost-of-privacy/) and [Javascript module pattern](http://briancray.com/posts/javascript-module-pattern) – Ron van der Heijden Aug 14 '13 at 10:35
  • Thanks for interesting article. It get's me some points, but don't answer the question( – Ph0en1x Aug 14 '13 at 11:11
  • Sorry, do not notice that you add 2nd article. Need to read it also. – Ph0en1x Aug 14 '13 at 11:18

3 Answers3

2

what is the difference between std and closureStd?

The std constructor creates a new method on every invocation while closureStd does not. You should've made it

function std(){}
std.prototype = {
    log: function(msg){ console.log("want to be private. " + msg) },
    logInfo: function(msg){ this.log(msg); }
};

And, of course (you already know) the log function in the closureStd is stored in a (private) variable while on the std instance it's accessible (and overwritable) from outside on each instance (or on their prototype). In the closure it's a variable lookup in the scope chain (which can assumed static), while for the method it's a property lookup on an object (and its prototype chain), which might be dynamic but is equally optimized in modern engines.

what is the price I need to pay to be able to call private methods from prototype?

None. The module pattern is common and cheap, variable lookups in a static chain are very fast. I'd rather worry about memory since you're creating so many method instances in the constructor approach.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

I also made some tests to measure performance (result's will be in console) and I find that putting class in closure demonstrate better performance compare to put methods in constructor. You also have inheritance options. So for now I don't see disadvantages and will always use class inside closure when I'll need private methods.

Ph0en1x
  • 9,943
  • 8
  • 48
  • 97
1

Note that the module pattern provided by the link Bondye provided does not hold private instance properties. It works great for function properties since the function would not change for each instance but works a little unpredictable for value properties as the following code demonstrates:

var module = (function () {
    // private variables and functions
    var foo = 'bar';
    // constructor
    var module = function (name) {
      // instance variables
      this.name=name;
    };
    // prototype
    module.prototype = {
        constructor: module,
        something: function () {
          // notice we're not using this.foo
          console.log("foo in "+this.name+" is:",foo);
          foo="new value";
        }
    };
    // return module
    return module;
})();

var m1 = new module("m1");
var m2 = new module("m2");
m1.something();// foo in m1 is: bar
m1.something();// foo in m1 is: new value
m2.something();// foo in m2 is: new value

As you can see in the last line of code both the m1 and m2 instance share a private variable called foo (all instances will point to the same value).

What I could make out from the other link that Bondye posted is that it's hard to simulate privateness in JavaScript and you could consider using a naming convention to indicate properties are private. You can use something like google closure compiler and annotate your JS code to indicate privates; but using closure compiler has it's own disadvantages (used libraries cannot be compiled unless Closure Compiler compatible and code has to be in certain format to be compiled in advanced mode).

Another option is to throw out prototype altogether (at least for everything using the private properties) and put everything in the constructor function's body (or use a function that returns an object).

// function returning an object

function makeObj(name){
  // private vars:
  var foo =  "bar";
  return {
    name:name,
    something:function(){
      console.log("foo in "+this.name+" is:",foo);
      foo="new value";
    }
  }  
}
var m1=makeObj("m1");
var m2=makeObj("m2");
m1.something();// foo in m1 is: bar
m1.something();// foo in m1 is: new value
m2.something();// foo in m2 is: bar

// constructor with everything in the constructor's body:

function Obj(name){
  // private vars:
  var foo =  "bar";
  this.name=name;
  this.something=function(){
    console.log("foo in "+this.name+" is:",foo);
    foo="new value";
  }
}
Obj.prototype.someOtherFunction=function(){
  // anything here can't access the "private" variables
}
var m1=new Obj("m1");
var m2=new Obj("m2");
m1.something();// foo in m1 is: bar
m1.something();// foo in m1 is: new value
m2.something();// foo in m2 is: bar

One more problem you can run into with using private instance values is that they are only accessible in the instance. When you want to clone an object and define a clone function in your object to create a new instance you have to write public accessor functions to set the private values because you can't set them directly as in Java private fields.

More info on using constructor functions here: Prototypical inheritance - writing up

Community
  • 1
  • 1
HMR
  • 37,593
  • 24
  • 91
  • 160
  • Thanks for your answer. First example was very intresting and it takes me some time to understand why this work that way. And now I see that closure isn't perfect variant for private fields, but initial question was about methods. Putting all the stuff in constructor isn't a good practice for my point of view mostly because of performance. – silent_coder Aug 15 '13 at 17:15
  • @silent_coder You are correct, the first example is good for private functions, it was code from the link provided by Bondye. Since SO scores high on google I thought it's good to mention that private instance values are not that easy. – HMR Aug 15 '13 at 23:44