Question

I've been using the Revealing Module pattern in my Javascript lately to help structure my code and everything has gone well. However, I'm a bit confused by this code snippet:

function vm() {
    var pub = function () {
        alert("from pub: " + this);
        pri();
    },
    pri = function () {
        alert("from pri: " + this);
    };

    return {
        pub: pub,
        pri: pri
    };
}
var it = new vm();
it.pub();
it.pri();

JSFiddle

When I call pub() and pri() directly, this refers to the current instance of vm. However, when I call pri() from within pub() suddenly this has reverted to referring to the global window object. I thought one of the objectives of the revealing module pattern was to remove the issues with this but it appears that when calling a function from within another function I'm losing the value of this.

Does anyone know why this if and if there's a way to get this to work without having to pass references to the current object around?

Was it helpful?

Solution

Your example combines three of the four ways in which to invoke a function.

Constructor Invocation

var it = new vm();

Inside of function vm, this refers to the object instance you are returning. This is expected.

Method Invocation

it.pub();

Inside of function pub, this refers to the same object instance as is referenced by it. Again, this is expected.

Function Invocation

pri();

Inside of function pri, this refers to the global object. This is not expected, and is considered to be a mistake in the JavaScript language. The 'pub' function was invoked with the method invocation pattern, and so it is natural to assume the this should always point to the current function/object when used inside it.

One remedy is to store your returned object in a local variable inside the vm method, and then due to scoping, pub and pri methods will be able to reference the object instance safely.

function vm() {
    var pub = function () {
        alert("from pub: " + that);
        pri();
    },
    pri = function () {
        alert("from pri: " + that);
    };

    var that = {
        pub: pub,
        pri: pri
    };

    return that;
}

OTHER TIPS

Calling pri() Inside pub actually calls the captured pri variable which is in scope. Calling it like this without a target object will set this to the global (window) object.

You may want to read about how this works in Javascript, because it is very much unlike other object-oriented languages you may know. this is dynamic and changes depending on how you invoke the method.

In your case the fix is easy enough: call the function like that: this.pri(). This will properly call the pri member of the current this object (i.e. var it), with this set to this... if this sentence makes any sense!

Never think you can omit this. in javascript code, like you could in C# or Java.

As others have it well-explained, I just provide you with a technic to keep your context tight on your object. You could use bind to tight your object with the current context. Caution, not all browsers supports it (old versions of IE fail). Besides the technic has enthusiasts and opponents.

return {
  pub: pub.bind(this),
  pri: pri.bind(this)
};

http://jsfiddle.net/zreFY/1/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top