Private JavaScript

With JavaScript, you can create private methods and properties using what Yahoo describes as the module pattern. Here's the basic construct, including a private method:

MyObject = function(){

  var privateMethod = function(){ /* do stuff */ };
  
  var obj = {
    publicProperty:5,
    publicMethod:function(){ /* do stuff */ };
  };
  
  return obj;
}(); // run it right away

If you're not familiar with this pattern, it's really quite cool. It takes advantage of closures, allowing the public methods to access the private methods. I've been using this approach in my recent work and it feels nice and works well.

Advantages to Private Methods

Private methods seem like a great idea because nobody can mess with them unless they have access to the JavaScript source and feel like rewriting things. It's also handy in that you've really established what your public API should be and there's no two ways about it. No underscores, no documentation. Just use the public methods because that's all you've got.

Having private methods also means that you're not polluting some other namespace with stuff that's never meant to be used by anything but your own code.

Disadvantages to Private Methods

Since they're private, it can make debugging marginally harder. This probably speaks more to my coding style but it's not unheard of for me to have Firebug open and just running a method from my object to see what happens instead of refreshing the page or what have you. But if the methods you want to examine or execute are private, then you have to jump back to the JavaScript source and try again. If you're trying to test this stuff on a server and need to FTP the info up, it just got even harder.

The other major disadvantage is that you've now made it harder for people to extend your code. JavaScript is really cool in that you can extend objects and prototypes at any time without ever having to touch the original code. But if I need to do anything that a private method does, then I need to rewrite that functionality in my own code or modify the original code.

Recommendation

Moving forward, I'll more than likely avoid private methods. I'm never one to go as far as saying, "X considered harmful" but with JavaScript and private methods, I don't think they're necessary.

What I'd recommend then is to create a utility or private object that, while, still public, makes it clear that these functions are really meant to be used within the namespace. There are two ways to which I'd approach this.

Utility Namespace

This one is pretty straightforward: just create a utility module on your namespace:

MyObject.util = {
  privateMethod: function(){ /* do stuff */ };
};

MyObject = function(){
  // shortcutting namespaces is still good
  var util = MyObject.util; 
  
  var obj = {
    publicProperty:5,
    publicMethod:function(){ util.privateMethod(); };
  }
  
  return obj;
}(); // run it right away

You'll notice I've made a shortcut to the utility object using a private property. This is perfectly fine as it makes your code easier to work with while still leaving the utility methods public.

Sub-module Pattern

I call this the sub-module pattern in that I declare everything within the container to take advantage of closures as a way of shortcutting my references.

MyObject = function(){
  var util = {
    privateMethod: function(){ /* do stuff */ };
  }
  
  var obj = {
    publicProperty:5,
    publicMethod:function(){ util.privateMethod(); };
  }
  
  // do my object attachment
  obj.util = util;
  return obj;
}(); // run it right away

Which of these two approaches you take will depend on code dependencies. If your utilities need to be used on multiple projects but everything else within the object doesn't, then declaring things separately makes sense (ala YUI). Otherwise, you can take advantage of the sub-module pattern to keep things clear.

Example Application

I used the sub-module pattern on a recent project. It was a calendar application much like Google Calendar with a small month view along with day, week and month views. Each calendar view became its own object within the calendar namespace that was defined. The great thing about this was that each of the calendars could basically talk to each other while still having access to some core common values like what the currently selected day, month and year was.

Published June 16, 2007
Categorized as JavaScript
Short URL: https://snook.ca/s/821

Conversation

19 Comments · RSS feed
alvin woon said on June 16, 2007

hail object literals in JS. :) Beside using it in namespace containers, I find it also very handy for emulating static objects and other contructs.

It is definitely one of the good stuff in JS and i like how you use it. Good work!

Peter Bex said on June 17, 2007

Private variables are useful in one other situation: When you're extending existing functions to do something additional. Example:


function somefunc() { ... };

(function() {
  var old = somefunc;
  somefunc = function() {
    alert('before somefunc');
    old.apply(this, arguments);
    alert('after somefunc');
})();

This prevents global namespace pollution with all kinds of 'old' function aliases.

Andy Kant said on June 18, 2007

I use private variables/methods pretty often to hide functionality that the user doesn't need to touch. However, for libraries that might be extended and need to access private variables, I provide an "expose" method that sets references to all private variables and methods in the current context. This might defeat the purpose of having private variables at all, but at the very least, it forces the person to have some idea what their doing before they can access them.

Jonathan Snook said on June 18, 2007

@Andy: but who is the user and would they want to touch them anyway? It's interesting that you have a method in which to expose private variables if the user wants to. It does create a barrier that forces the user to think about the decision before they need to. I'm just not sure you even need to go private to begin with.

Andy Kant said on June 18, 2007

@Jonathan

Well, I've only used that in one particular case so far...

I wrote an ActiveRecord-inspired extensible database system in JavaScript. It has a layering mechanism where any method (whether public or private) can have preprocessors and postprocessors attached to it in order to add additional functionality in which case the attached functionality would need access to all internal data.

Specifically what I'm using it for is that the base database library is fairly slim, only containing enough logic to be functional. On top of this, I have a separate validation module that will attach itself to every appropriate method in the library that adds data validation primarily but could also be used to add something like constraint management. The validation module needs to add validation steps to internal/private methods as well as potentially look at the primary/foreign keys stored within the raw data so I needed the ability to expose it when necessary. Another example is that I have an unfinished SQL query module for it that needs to be able to access the raw data in order to return its result set.

I don't want to expose raw data such as the primary/foreign key indexes or data tables unless they're needed because if someone doesn't know what they're doing they can corrupt the entire database.

Anyways...you're right, I don't *need* to go private, its just an added measure to maintain data integrity. Data integrity alone can be enough to make it worthwhile, although its probably overkill in most cases.

Michael Jackson said on June 19, 2007

One place where the Yahoo! guys use this technique is in the YAHOO.util.Anim class. There is a private variable called isAnimated. It's a variable that you just don't want users messing with. It only serves to inform the AnimMgr object. It has an accessor method but that's it.

If the variable were public, and the user decided to set it to false while an animation was running, the animation would remain in the AnimMgr queue, forcing the AnimMgr to loop over it on every frame of the animation, but actually doing nothing. Then, when you wanted to start the animation going again, you would have to set the boolean to true and then manually restart the AnimMgr. So it's messy, and it's a two step process later on to restart the thing.

In my opinion, this is the perfect case for a private variable. It's just not a good idea to touch the thing!

Jonathan Snook said on June 19, 2007

@Michael Jackson: In the post, I tried to be specific in saying that private methods should be avoided. Private properties are less of an issue as properties hold state and not logic. Although, even then, if you have multiple pieces relying on that variable, then extending that class becomes more difficult as any new methods won't have access to those private variables.

There has to be an assumption that if someone is extending your code, that they hold the power, not you. Trying to hide the code in private methods or variables just means that it's harder for people to extend and ultimately may mean modifying your code directly to get the job done.

Michael Jackson said on June 19, 2007

@Jonathan: Excellent point. On a second read, I realize that my comment was a bit off topic, and I tend to agree with your points.

Jack Turner said on June 20, 2007

Your code example can be made even clearer by returning the object containing the public properties and functions rather than storing it in the "obj" variable:

MyObject = function(){

  var privateMethod = function(){ /* do stuff */ };

  return {
    publicProperty:5,
    publicMethod:function(){ /* do stuff */ };
  };
}(); // run it right away


Any downsides to this?

Jonathan Snook said on June 20, 2007

@Jack Turner: I like attaching it to the object as it's clear at the bottom of the function what I'm doing. If I have more than a couple functions then I have to scroll up to see where the object literal starts. And it more closely matched the second example, which again makes it clear to me what it is I'm attaching before returning the object. But this is purely preference.

Rubiwachs said on June 22, 2007

Jonathan, could you elaborate more about your calendar example in 'code'?
How do you mean:

"The great thing about this was that each of the calendars could basically talk to each other while still having access to some core common values like what the currently selected day, month and year was."

I'd like to see how you approached this.

Jonathan Snook said on June 22, 2007

@Rubiwachs: Unfortunately, it was for a client project, so I'm not allowed to publish what I did. The structure is much like that last example though where private objects are attached to a central object that gets returned. Internal calls use the internal API and external calls can use the external API.

Rubiwachs said on June 26, 2007

I was not looking for the code itself :), I am only interested in the structure of the code => 3 objects in the same namespace, accessing common values.
Would you do it like this:


if (typeof(MyNamespace) == 'undefined') var MyNamespace = {};

MyNamespace.MyObject1 = function() {
  var util = {
    _getValue: function() { return MyNamespace.value; },
    _setValue: function(value) { MyNamespace.value = value; }
  }

  var obj = {
    init: function() {},
    getValue: function() { return util._getValue(); },
    setValue: function(value) { util._setValue(value); }
  }

  obj.util = util;
  return obj;
}();

MyNamespace.MyObject2 = function() {
  var util = {
    _getValue: function() { return MyNamespace.value; },
    _setValue: function(value) { MyNamespace.value = value; }
  }

  var obj = {
    init: function() {},
    getValue: function() { return util._getValue(); },
    setValue: function(value) { util._setValue(value); }
  }

  obj.util = util;
  return obj;
}();

// set currentValue via MyObject1
MyNamespace.MyObject1.setValue('test1');

// retrieve currentValue via different objects
alert(MyNamespace.MyObject1.getValue());
alert(MyNamespace.MyObject2.getValue());

Both alert's will return 'test1'.
Any thoughts?

Jonathan Snook said on June 26, 2007

In the case of the calendar project, it was set up like this:

calendar = function(){
  var cal = { d:1, m:1, y:2006 }
  var monthView = {
     getEvents:function(){
         var url = '/getevents?d= ' + cal.d
                    + '&m=' + cal.m
                    + '&y=' + cal.y;
         Ajax.call(url);
     }
  }
  cal.month = monthView;
  return cal;
}();

This is more of a pseudo-code but you can see that the monthView object is still available externally via the calendar.month object and internally via the monthView object. Likewise, the monthView object can access the cal object and any of its properties. I had an object for both the day and weekly views as well, attached to the cal object in the same way.

DarrylHebbes said on August 29, 2007

How would one go about setting the 'publicProperty' in the sub-module pattern from another method in the object.

for example:

MyObject = function(){
  var util = {
    privateMethod: function(){ 

       obj.publicProperty = 10;  // <- Is this possible?
    };
  }

  var obj = {
    publicProperty:5,
    publicMethod:function(){ util.privateMethod(); };
  }

  // do my object attachment
  obj.util = util;
  return obj;
}(); // run it right away
Jonathan Snook said on August 29, 2007

@DarrylHebbes: you hit it on the nose. You can access methods of other objects within that scope. It makes a handy shortcut and is exactly how I usually approach things.

DarrylHebbes said on August 29, 2007

Thanks very much, been reading your posts since 2002...

rubudgirl said on January 16, 2009

какие праздники вам нравятся?

holremasha said on January 17, 2009

А как зовут ваших зверюшек?
У меня кот Барс (балбес еще тот)
Кошка Мусёна

Sorry, comments are closed for this post. If you have any further questions or comments, feel free to send them to me directly.