views:

3336

answers:

3

I'm curious as to if there are any best practices relating to JQuery when constructing encapsulated code blocks.

Generally, when I construct a page I like to encapsulate the functions used within that page inside an object. This allows me some encapsulation when building applications. There's nothing I hate more than seeing a JavaScript file with a bunch of this

function doSomethingOnlyRelevantOnThisPage() {
    // do some stuff
}

I this makes for messy design, and doesn't really encapsulate functionality nicely.

Commonly in many frameworks, there is a standard that is used to perform this encapsulation.

In Mootools they favor the Object Literal Notation:

var Site = {        
    // properties and methods
}

In YUI they favor the Self Executing Function notation:

(function() { // properties and methods })()

The nice thing about the second example is that a closure is created, thus allowing you to define private properties and methods.

My question is this: Do any JQuery aficionados have any best practices for creating these cleanly encapsulated structures? What is the rationale behind their use?

+1  A: 

I usually follow the prototype pattern:

MyFunction = function(param1, param2)
{
   this.property1 = param1;
   // etc.
}

MyFunction.prototype =
{
    memberOne: function(param1)
    {
       // ...
    },

    memberTwo: function(param2)
    {
    }
}

You get something a "constructor" (the function itself) and encapsulated "methods" and "fields".

It's easier for someone who is used to class-based OO languages :)

Tsvetomir Tsonev
But this is only useful if you plan to encapsulate state within the objects. You would have to call new on these objects to create instances. In my case, they would be behaving more like a static class in OO terms.
steve_c
True, true... in this case I would prefer self-executing anonymous functions.
Tsvetomir Tsonev
+3  A: 

I use YUI and jQuery when developing (YUI widgets and a few convenience functions, jQuery selectors and javascript "extensions"), and the general javascript template I use is this:

/*global YAHOO, $ */

// Create the public-scope accessable namespace for this page
YAHOO.namespace('Project');

YAHOO.Project.page = function() {
    // Private members

    var self = {};

    // Public members
    var pub = {};

    pub.init = function() {

    };

    return pub;
} ();

// When the DOM is loaded, initialize this module
$(document).ready(YAHOO.Project.page.init);

Now clearly, you can remove the YAHOO.namespace() call if you don't want to use YUI, but that's the basic outline. It uses object literal notation, but also allows you to define private properties and methods.

Just remember that when calling private members or referencing private variables to reference them as self.funcName(). You can define them outside of the self object, but then you get a mismash everywhere in your object, where you're trying to figure out if size_of() is a private method or defined globally somewhere else.

Dan Hulton
+1  A: 

Since I've been working with jQuery for a while now, I've decided on a standard pattern that works well for me.

It's a combination of the YUI module pattern with a bit of jQuery plugin pattern mixed in.. We ended up using the self executing closure pattern. This is beneficial in a few ways:

  1. It keeps code to a minimum
  2. It enforces separation of behavior from presentation
  3. It provides a closure which prevents naming conflicts

This is what it looks like:

;(function($) {        
    var myPrivateFunction = function() {
    };

    var init = function() {
        myPrivateFunction();
    };

    $(init);
})(jQuery);

We realized that assigning the result of the function execution, similar to the YUI module pattern, exposes code that could potentially be called from within presentation code. We want to prevent this, so this pattern fits.

Of course we could have written the init method inline, without defining a variable for the function. We agreed that explicitly defining the init function made the code clearer to readers.

What happens if we want to share functions between pages/external js files? We simply hook into the existing mechanism that jQuery provides for extending the jQuery object itself - the extend function.

If the functions are static, we use $.extend, and if they operate over a wrapped set, we use the $.fn.extend function.

Hope this helps someone.

steve_c
I keep seeing this pattern, but I'm yearning for a fuller example - I've got a page with a few distinct and fairly involved interactive elements whose logic should be encapsulated apart from one another. Any suggestions for organizing code in that sort of situation? Using $.fn.extend for each different UI piece seems counter intuitive.
Brent Dillingham
I definitely wouldn't advocate using extending the jquery function unless you are writing a plugin - so something that is reusable in many pages. I would, in your case, break my functionality up into its distinct parts, creating a self executing function to contain that logic in its own closure. Any shared code can then be attached to jQuery itself via $.extend, which would allow you to have helper functions that don't require the context of an element to function.
steve_c