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.
Conversation
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!
Private variables are useful in one other situation: When you're extending existing functions to do something additional. Example:
This prevents global namespace pollution with all kinds of 'old' function aliases.
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.
@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.
@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.
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 theAnimMgr
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 theAnimMgr
queue, forcing theAnimMgr
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 totrue
and then manually restart theAnimMgr
. 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!
@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.
@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.
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:
Any downsides to this?
@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.
Jonathan, could you elaborate more about your calendar example in 'code'?
How do you mean:
I'd like to see how you approached this.
@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.
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:
Both alert's will return 'test1'.
Any thoughts?
In the case of the calendar project, it was set up like this:
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.How would one go about setting the 'publicProperty' in the sub-module pattern from another method in the object.
for example:
@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.
Thanks very much, been reading your posts since 2002...
какие праздники вам нравÑÑ‚ÑÑ?
Ркак зовут ваших зверюшек?
У Ð¼ÐµÐ½Ñ ÐºÐ¾Ñ‚ Ð‘Ð°Ñ€Ñ (Ð±Ð°Ð»Ð±ÐµÑ ÐµÑ‰Ðµ тот)
Кошка МуÑёна