views:

199

answers:

2

Hi folks, I'm trying to create my custom toolbox which imitates jQuery's design pattern. Basically, the idea is somewhat derived from this post: http://stackoverflow.com/questions/2061501/jquery-plugin-design-pattern-common-practice-for-dealing-with-private-function (Check the answer given by "David").

So here is my toolbox function:

(function(window){
    var mySpace=function(){
        return new PrivateSpace();
    }

    var PrivateSpace=function(){
        var testCache={};
    };    

    PrivateSpace.prototype={
        init:function(){
            console.log('init this:', this);
            return this;
        },
        ajax:function(){
            console.log('make ajax calls here');
            return this;
        },
        cache:function(key,selector){
            console.log('cache selectors here');
            testCache[key]=selector;
            console.log('cached selector: ',testCache);
            return this;
        }
    }
    window.hmis=window.m$=mySpace();
})(window)

Now, if I execute this function like:

  console.log(m$.cache('firstname','#FirstNameTextbox'));

I get an error 'testCache' is not defined. I'm not able to access the variable "testCache" inside my cache function of the prototype. How should I access it? Basically, what I want to do is, I want to cache all my jQuery selectors into an object and use this object in the future.

+1  A: 

The prototype pattern does not allow per-instance private variables.

You can either use a private cache that will be accessed by all instances of PrivateSpace (by declaring the cache inside your outer most closure, or stop using the prototype pattern.

Matt
@Matt: by the way, how is jQuery solving this issue? Doesn't it use private variables at all? I have the same questions for u as well, which I asked Sean above.
novogeek
+5  A: 

testCache is hidden in the closure that new PrivateSpace creates. The correct pattern to use here is

var PrivateSpace=function(){
    this.testCache={};
};   

PrivateSpace.prototype={
    cache:function(key,selector){
        this.testCache[key]=selector;
        return this;
    }
}

The essential part here is this.

But the entire piece of code seems a bit contrived - there is no reason to use a prototype pattern when only a single instance is to be created. You should instead rely on variables accessible through a shared scope (closure).

(function(window)(
     var cache = {}, mylib;

     window.mylib = mylib =  {
          cache: function(key, selector) {
              cache[key] = selector;
              return mylib;
          }
     }

})(window);

Update
And by the way, do not follow the jQuery pattern without having a real reason to do so ;)

Update
A better approach for PrivateSpace could be

function PrivateSpace(){
    var cache = {};
    return {
        cache: {
            get: function(key){
                return cache[key];
            },
            set: function(key, value) {
                cache[key] = value;
            }
         },
         init: function() {
             ...
         }
     };
 }

This is the pattern normally used for providing private members..

Sean Kinsey
@Sean,Thanks for the quick reply.For Answer1: In PrivateSpace, I dont want to say this.testCache and expose it to the outside world. I want a set of private variables which the inner functions use. Do you mean to say if I go with prototype, I cant use private variables with shared scope?For Answer2: I have few functions which should return a new instance. How does the closure which u suggested help me in that case? Also, I'm looking for chaining the methods so that I can act on the same instance. Can that be done?
novogeek
Then you will need to place it in a common scope. But then all instances of PrivateSpace will share it.I've updated the answer with a better approach for PrivatSpace
Sean Kinsey
@Sean: Awesome! I was struggling around the same point. I was using revealing module pattern instead (http://www.wait-till-i.com/2007/08/22/again-with-the-module-pattern-reveal-something-to-the-world/).This approach looks fine. I'l get back if I find any issues in my project. Thanks a lot :)
novogeek