Monday, April 4, 2011

jQuery OOP - Encapsulation

Since I already include jQuery in every project I work on. I figured why not try to implement some features of OOP within the framework of a jQuery plugin. In this post I'll be outlining how to implement some useful features of encapsulation.

The full object and examples can be found here.

Frame and Public/Private Functions

I would like to thank my friend Zach for the plugin method utilized in this code. The plugin reads in the method name and calls it from an object's methods. These methods can then be indirectly called outside of the plugin (ie. $(obj).plugin("function") ):
(function($) {
     var methods = {
          init : function(options) {              
               var settings = {
                    ...
               };
               $.extend(this, settings, options);
               
               $t = $(this);
               $t.each(function(){
                    ...
               });
               return this;
          },
          func1 : function(){}
     },

     $.fn.object = function(method) {
          if (methods[method]) {
               return methods[method].apply(this,
                             Array.prototype.slice.call(arguments, 1));
          } else if (typeof method === 'object' || !method) {
               return methods.init.apply(this, arguments);
          } else {
               $.error('Method ' + method + ' does not exist on jQuery.');
          }
     };
})(jQuery);     
The functions contained in the methods object also return values as expected. Since these functions are accessible outside of the plugin, and other functions defined inside the plugin are not; it is then possible to create public and private functions.
(function($) {
     //public functions
     var methods = {
          ....
          foo : function(){
               ...
          },
          bar : function (){
               //call private function
               privy.apply(this);
          }
     },
  //private functions
     function privy(){
          ...
     }
    ...
})(jQuery);     
The apply function is used to maintain consistent scoping for the this pointer. apply() should be used whenever the called function needs to reference the this object. To call the public version of a method inside of the plugin you have to call it from the methods object, (ie. methods.bar.apply(this)). Once instance variables are implemented, private methods can be used as getters and setters.

Class and Instance Variable
To attatch instance variables to individual objects, I used the $.extend function to attach the passed options object to this:
(function($){
     //public functions
     var methods = {
          init : function(options) {              
               $.extend(this, settings, options);
               //apply functionality to every member of the set sent in    
               $(this).each(function(){});
               return this;
          }
     ...
})(jQuery);     
Now these instance variables are accessible throughout the plugin.

The apply method should be used to call methods from inside the plugin. Otherwise this will be defined as the methods object (public methods) or the wrapping function itself (private methods).
(function($){
     //public functions
     var methods = {
          init : function(options) {              
               //default instance vars
               var settings = {
                    name : ""
               };
               $.extend(this, settings, options);
               //apply functionality to every member of the set sent    
               $(this).each(function(){});
               return this;
          },
          foo : function(){
               console.log(this.name);
          },
          bar : function (){
               bar.apply(this);
          }
     },
     ...
     function bar(){
          console.log(this.name);
     }
     ...
})(jQuery);     
Class variables are even simpler to implement, for example the methods object is a class variable. Any variable instantiated in the same scope will be a class variable.
(function($){
     var methods = {
     ...
     },
     //class variables
     class1 = 0;
     //private functions
     function bar(){
          class1++;
          console.log(class1);
     }
     ....
})(jQuery);     
Summary
In this post I've show how to implement parts of encapsulation within a jQuery plugin. Instance and class variables, as well as public and private methods were implemented. I figure thats a pretty good start.

2 comments:

  1. Nice work Ross. I'm a little confused about the "query" in the private function bar(). What does it do?

    ReplyDelete
  2. That is a typo. thanks for the catch. Has been edited out.

    ReplyDelete