How to preserve javascript "this" context inside singleton pattern?

I have something similar to this:

var a = (function () {

    return {

        b: 1,
        c: function () {

            console.log(this.b);
        }
    };
})();

So,

a.c(); // = 1

But if I do

b = 2;
a.c.apply(this); // = 2

Is it possible to preserve the context of "this" inside "ac()" without changing (too much) the structure of "a" object? I don't have the control of the function's call, so I'd need a workaround to deal with this inside the object itself.

UPDATE :

To be more specific, this is the structure of my files:

Structure 1 (singleton like pattern):

var a = (function () {

    var _instance;

    function init() {

        return {

            b: 1,
            c: function () {

                console.log(this.b);
            }
        };
    }

    return {

        getInstance: function () {

            if (_instance === undefined) {
                _instance = init();
            }

            return _instance;
        }
    }
})();

Structure 2:

var b = {

    c: 1,
    d: function () {
        console.log(this.c);
    }
};

SOLUTION :

I have implemented a solution based on Mahout's answer, spliting the return statement inside init(), so it remains safe for the object context (and the instance) under any situation.

For singleton pattern:

var a = (function () {

    var _instance,
        self;

    function init() {

        return self = {

            b: 1,
            c: function () {

                console.log(self.b);
            }
        };
    }

    return {

        getInstance: function () {

            if (_instance === undefined) {
                _instance = init();
            }

            return _instance;
        }
    };
})();

For object literal:

var b = (function () {

    var self;

    return self = {
        c: 1,
        d: function () {
            console.log(self.c);
        }
    };
})();

So

a.getInstance().c(); // 1
a.getInstance().c.apply(this); // 1
setTimeout(a.getInstance().c, 1); // 1
$.ajax({ complete: a.getInstance().c }); // 1

You can slightly change the way you are returning the object from the anonymous function:

var a = (function () {
   var result = {};
   result.b = 2;
   result.c = function() {
     console.log(result.b);
   };
   return result;
})();

This should have the same effect, however it does remove the use of this .

If you can't afford to change the structure of a this much, then alternately you can (much) more dangerously use:

a.c.apply = function() { // Stops the apply function working on a.c by overriding it
    return a.c();
}

If you choose this though you must be wary that anytime acapply is used it will no longer work 'as expected' - it will fix the issue presented here though.


I made this pen to illustrate the differences,I hope it helps:

http://codepen.io/dieggger/pen/BNgjBa?editors=001

var a = (function () {
    return { b: 1,
             c: function () {
              console.log(this.b);
            }
    };
})();


a.c(); //prints 1


b = 2; // global variable "b" which is being hoisted BTW


// The following will act like this:

//it throws "cannot read property 'apply' from undefined" 
//though it prints "1" since the first part invokes the "c" function 
//inside of the"a" module which has the console.log

a.c().apply(this); 


//In this case "this" is the window object which has the variable "b"
a.c.apply(this); // it'll print 2

You can do this:

var a = (function ()
{
    return {
        b: 1,
        c: function ()
        {
            console.log(this.b);
        }
    }
})();

var decorator = function() { return a; };

var b = 2;

decorator.call(this).c(); // => 1

Basically it looks like you want to bind the IIFE, and not the object that it returns, to the outside scope, so that the nested returned object preserves the value of the interior b .

链接地址: http://www.djcxy.com/p/28394.html

上一篇: 无法访问VPN连接后运行的本地服务器

下一篇: 如何在单例模式中保存javascript“this”上下文?