Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS Module Pattern's public method as callback victim. (this-issue)

I spent the better part of the day reading about the module pattern and its 'this' scope. Eventually I found a work-around for my problem, although with a feeling there's a better way of doing things.

The actual code is >200 lines, but I've boiled it down to the following: objA has a method (publicA) that objB wants invoke by callback. The detail that complicates things is that publicA needs help from publicA_helper to do its job. (http://jsfiddle.net/qwNb6/2/)

var objA = function () {
    var privateA = "found";
    return {
        publicA: function () {
            console.log("privateA is " + this.publicA_helper());
        },
        publicA_helper: function () {
            return privateA;
        }
    };
}();

var objB = function () {
    return {
        callback: function (callback) {
            callback();
        }
    }
}();

objA.publicA(); // privateA is found
objB.callback(objA.publicA); // TypeError: Object [object global]

Fair enough – I've grasped that the caller's context tends to influence the value of 'this'. So I add measures to retain 'this' inside objA, of which none seems to work. I've tried the var objA = (){}.call({}) thingy, setting var self = this; (calling self.publicA_helper() accordingly). No luck.

Eventually, I added a private variable var self;, along with a public method:

init: function() {self = this;},

...and by making sure I call objA.init(); before passing objA.publicA to objB.callback, things actually work.

I cannot stress the immensity of the feeling that there's a better way of doing this. What am I missing?

like image 436
o-o Avatar asked Dec 16 '25 17:12

o-o


1 Answers

The generalized solution is extremely simple.

Write all the module's methods as private, then expose those that need to be public.

I write all my modules this way :

var objA = function () {
    var privateA = "found";
    var A = function () {
        console.log("privateA is " + A_helper());
    },
    var A_helper = function () {
        return privateA;
    }
    return {
        publicA: A
        //A_helper need not be exposed
    };
}();

Thus, all methods are in the same scope, each one having direct access to all other methods in the same module, and the ambiguous this prefix is avoided.

objB.callback(objA.publicA); will now work as expected.

See fiddle

like image 161
Beetroot-Beetroot Avatar answered Dec 19 '25 19:12

Beetroot-Beetroot