Robin Heggelund Hansen
Robin Heggelund Hansen

Reputation: 5006

Would this be a good way to do private functions?

Just saw some interesting code while doing a typo in coffee-script. I got the following code

var Mamal, mam;

Mamal = (function() {
  var __priv_func;

  function Mamal() {}

  Mamal.prototype.simple_var = 5;

  Mamal.prototype.test = function() {
    return __priv_func(this);
  };

  __priv_func = function(instance) {
    return alert(instance.simple_var);
  };

  return Mamal;

})();

mam = new Mamal();
mam.simple_var = 10;
mam.test();

Now I've read alot about the module pattern in javascript and why its a bad thing (takes more memory, longer to create...) but of course the upside is having truly private functions/variables. Wouldn't the above code be a good way to create private functions (this wouldn't work for variables, unless you wanted static private variables) as the function is only created once in the closure?

One of the upsides of the module pattern is also the execution speed of functions as the code doesn't have to look up the prototype chain. Would this theoretically give the same speed improvements?

Upvotes: 7

Views: 317

Answers (2)

RightSaidFred
RightSaidFred

Reputation: 11327

To highlight the points I was making, because clearly there was more to the question than just the title:

  • Yes a module pattern is a good and commonly used way to create private (er, local) data (functions or whatever), and export some sort of interface. Since a function is the only way to create variable scope, it's the only way to create private functions.

  • Because the functions will be shared by all objects created from Mamal, they're not useful for a functional inheritance pattern (references to functional inheritance have been removed from the question).

  • There's no performance improvement over lookups in the prototype chain, because the prototype chain needs to be traversed anyway just to get to your private functions.


To address specific questions points in the updated post:

"Would this be a good way to do private functions?"

Sure, but that's because having a function nested in another is the only way to scope a function.

"Now I've read alot about the module pattern in javascript and why its a bad thing..."

For a one-time use module, I don't see any issue. Also, any data referenced by variables that are no longer needed after the module function exits is free for garbage collection. This wouldn't be the case if they were global, unless you nullified them.

"...of course the upside is having truly private functions/variables..."

Yes, though some would take exception to the use of the word "private". Probably "local" is a better word.

"...this wouldn't work for variables, unless you wanted static private variables..."

Yes, though again some may take exception to the use of the word "static".

"Wouldn't the above code be a good way to create private functions...as the function is only created once in the closure?"

Yes again, nested functions are the only way to make them "private" or rather local.

But yes, as long as the function only ever needs to access the public properties of the objects (which are accessible to any code that can access the object) and not local variables of the constructor, then you should only create those functions once, whether or not you use a module pattern.

"One of the upsides of the module pattern is also the execution speed of functions as the code doesn't have to look up the prototype chain. Would this theoretically give the same speed improvements?"

No, you haven't exported your private functions directly, but rather the only way to call them is by traversing the prototype chain.

But if you ditched the prototype chain, and added functions as properties directly on the objects created, then you'd have some improvement there.

Here's an example:

Mamal = (function() {
  var __priv_func;

  function Mamal() {
    this.test = __priv_func;
  }

  Mamal.prototype.simple_var = 5;

  __priv_func = function() {
    return alert( this.simple_var );
  };

  return Mamal;

})();

Now you've eliminated the prototype chain in the lookup of the test function, and also the wrapped function call, and you're still reusing the __priv_func.

The only thing left that is prototyped is the simple_var, and you could bring that directly onto the object too, but that'll happen anyway when you try to modify its value, so you might as well leave it there.


Original answer:

If you're talking about a module pattern, where you set up a bunch of code in (typically) an IIFE, then export methods that have access to the variables in the anonymous function, then yes, it's a good approach, and is pretty common.

var MyNamespace = (function () {
    // do a bunch of stuff to set up functionality
    //    without pollution global namespace

    var _exports = {};

    _exports.aFunction = function() { ... };
    _exports.anotherFunction = function() { ... };

    return _exports;
})();

MyNamespace.aFunction();

But in your example, I don't see and advantage over a typical constructor, unless you decide to use the module pattern as above.

The way it stands right now, the identical functionality can be accomplished like this without any more global pollution, and without the wrapped function:

var Mamal, mam;

Mamal = function() {};

Mamal.prototype.test = function() {
    return console.log(this.simple_var);
};

Mamal.prototype.simple_var = 5;

mam = new Mamal();
mam.simple_var = 10;
mam.test();

" Wouldn't the above code be a good way to create private functions (this wouldn't work for variables, unless you wanted static private variables) as the function is only created once in the closure?"

Given the rewritten code above, the function is still only created once. The prototype object is shared between objects created from the constructor, so it too is only created once.

"One of the upsides of functional inheritance is also the execution speed of functions as the code doesn't have to look up the prototype chain. Would this theoretically give the same speed improvements?"

In your code, the function is called via a function in the prototype chain, so it has that same overhead, plus the overhead of finding the local function in the variable scope and invoking that function as well.

So two lookups and two function invocation instead of one lookup and one invocation.

Upvotes: 1

user1087079
user1087079

Reputation: 1356

var Mamal, mam1, mam2;

Mamal = (function() {
  //private static method
  var __priv_func = function() {
    return 1;
  };

  function Mamal() {
  }

  Mamal.prototype.get = function() {
        return __priv_func();
  };

  Mamal.prototype.set = function(i) {
        __priv_func = function(){
          return i;
        };
  };

  return Mamal;

})();

mam1 = new Mamal();
mam2 = new Mamal();
console.log(mam1.get()); //output 1
mam2.set(2);
console.log(mam1.get()); //output 2

The function __priv_func is not only private, but also static. I think it's a good way to get private function if 'static' does not matter.

Below is a way to get private but not static method. It may take more memory, longer to create.......

var Mamal, mam1, mam2;

function Mamal() {
  //private attributes
  var __priv_func = function() {
    return 1;
  };

  //privileged methods
  this.get = function() {
      return __priv_func();
  };
  this.set = function(i) {
      __priv_func = function(){
        return i;
      };
  };
}

mam1 = new Mamal();
mam2 = new Mamal();
console.log(mam1.get()); // output 1
console.log(mam2.get()); // output 1
mam2.set(2);
console.log(mam1.get()); // output 1
console.log(mam2.get()); // output 2

Upvotes: 0

Related Questions