views:

55

answers:

2

I'm having trouble referencing the desired object when I've namespaced functions.

No problems here:

obj.test = function() {
  // this == obj
}

But I'm getting tripped up when I namespace:

obj.namespace.test = function() {
  // this == namespace
}

In the latter example, I know this references namespace, but I want to reference obj. How can I do it?

+1  A: 

There is no simple answer, but you have a few options:

obj.namespace.test = function () {
  return (function () {
     // this == obj
  }).apply(obj, Array.prototype.slice.call(arguments));
};

This returns a function that is bound to obj. Unfortunately, if obj is reassigned, this will not work, because it's a live reference. This is more robust:

obj.namespace.test = (function (obj) {
   return function () {
     return (function () {
        // this == obj
     }).apply(obj, Array.prototype.slice.call(arguments));
   };
}(obj));

As you can see, neither of these is very clean. You might ask yourself why you depend on this to begin with. Using a normal reference to obj is obviously the most straightforward approach.

bcherry
+1  A: 

Others have made some good suggestions.

I just wanted to add you can also make namespace a function that will return an object with a variable pointing to the obj and whatever member functions you want.

Example:

    // Note that "namespace" is a reserved word in JS for some reason,
    //  so you can't use it as a variable/function/etc name.
    var myNamespace = function myNamespace(){
        var that = this;

        var test = function test(){
            //in here use this.that to point to obj
            alert(this.that.name);
        };

        return {that: that, test: test};
    };

    // Then create the obj:
    var obj = { name: "Mr. Ahb Jeckt", myNamespace: myNamespace};

    // Then you can just call the "namespace" and member function like this:
    obj.myNamespace().test();


    //Or, "initialize" the namespace and call it like so:
    obj.myNamespace = obj.myNamespace();
    obj.myNamespace.test();

    obj.name = "Mrs Ahb Jeckt";
    obj.myNamespace.test();

This way there are no hard-coded references to obj in the "namespace" itself, and I think it's pretty clean.

This also works if obj is a "class"; just make obj a constructor instead of an object literal:

// Then create the obj:
var obj = function (name){
    this.name = name || "unnamed";
    this.myNamespace = myNamespace;

    // Initialize the namespace, we can leave this out and just reference
    //    obj.myNamespace() each time as well

    this.myNamespace = this.myNamespace();
};

// Then you can just call the "namespace" and member function like this:

var myObj = new obj("Mr Ahb Jeckt");
myObj.myNamespace.test();

var myObj2 = new obj("Mrs Ahb Jeckt");
myObj2.myNamespace.test();
MisterMister