3

I'm trying to create my custom toolbox which imitates jQuery's design pattern. Basically, the idea is somewhat derived from this post: jQuery plugin design pattern (common practice?) for dealing with private functions (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.

Community
  • 1
  • 1
novogeek
  • 67
  • 7
  • I'm not really sure what this gets you, other than being slower/more verbose, if you cached the actual jQuery objects that you want to point to there's some benefit, but as it is I'm having trouble seeing how this actually saves you time, code, or performance. Can you explain a bit better what your goal is with this, or the reason you need the mapping? – Nick Craver May 15 '10 at 13:31
  • @Nick: am working in a huge jQuery based project with over 600 .js files. The DOM is very complex in the app & over 30 plugins are being used. There are complex selectors being used in loops, which are adding to the performance hit. I'm trying to cache the selectors in an object and use it from the object, instead of querying the DOM element again and again. – novogeek May 15 '10 at 16:08

2 Answers2

5

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
  • 37,689
  • 7
  • 52
  • 71
  • 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 May 15 '10 at 16:27
  • 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 May 15 '10 at 18:02
  • 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 May 15 '10 at 19:20
1

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
  • 74,352
  • 26
  • 153
  • 180
  • @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 May 15 '10 at 16:38