Alex Rivera | Logout

jQuery plugin design pattern (common practice?) for dealing with private functions

Asked 2010-01-14T00:53:25.883
9

I've been developing jQuery plugins for quite some time now, and I like to think I know how to design one well by now. One issue keeps nagging me though, and that is how to deal with private functions in a powerful yet elegant manner.

My plugins generally look something like this:

(function($) {

  $.fn.myplugin = function(...) {
    ...
    // some shared functionality, for example:
    this.css('background-color', 'green');
    ...
  };
  $.fn.mypluginAnotherPublicMethod = function(...) {
    ...
    // some shared functionality, for example:
    this.css('background-color', 'red');
    ...
  };

}(jQuery));

Now my question is: how to neatly DRY up that shared functionality? An obvious solution would be to put it in a function within the plugin's namespace:

var fill = function($obj, color) {
  $obj.css('background-color', color);
};

Although this solution is effective and nicely namespaced, I really dislike it. For one simple reason: I have to pass it the jQuery object. I.e. I have to call it like this: fill(this, 'red');, while I would like to call it like this: this.fill('red');

Of course we could achieve this result by simply putting fill into jQuery.fn. But that feels very uncomfortable. Imagine having ten plugins developed based on this approach and each plugin putting five of those 'private' functions into the jQuery function namespace. It ends up in a big mess. We could mitigate by prefixing each of these functions with the name of the plugin they belong to, but that doesn't really make it more attractive. These functions are supposed to be private to the plugin, so we do not want to expose them to the outside world at all (at least not directly).

So there's my question: does anyone of you have suggestions for how to get the best of both worlds. That is; plugin code being able to call 'private' plugin functions i

Edit
Report

1 Answer

1

Unfortunately, "private" methods (or any property for that matter) can never be called with a "this" prefix in javascript. Anything which is called like this.myFunc(myArgs) must be publicly available.

And "private" methods can only be called from within the scope in which they were defined.

Your original solution is the only one that will work. Yes, it's a pain having to pass in this, but there's no more verbosity than there would be if your impossible request was possible:

this.fill('green');
//or
fill(this,'green');

As you can see, they both take up exactly the same number of characters in your code.

Sorry to say, but you're stuck with this as a solution, unless you want to create a new namespace and make them not private - which is simply going to add to the amount of code you need to write, i.e. what you indirectly called "not directly exposed":

this.myplugin.fill('green');

...is more verbose, thus kind of defeats the purpose.

Javascript is not like other languages, there are no "private" members per-se, only members accessible within closures, which can sometimes be used in a similar way to private members, but is more of a "workaround", and not the "real-deal" private members you are looking for.

It can be difficult to come to terms with this (I often struggle), but don't try to mould javascript into what you understand from other languages, take it for what it is...

answered 2010-01-14T01:59:14.297

Your Answer