laurent
laurent

Reputation: 90756

How can I access "this" from within a JavaScript module?

I'm trying to understand how to best use the JavaScript module pattern. My problem is that it seems there's no way to refer to the module from within itself, because this is set to the Window object.

I've got this simple test code:

var Test = function() {
    var that = this;

    return {
        something: function() {
            console.info(that);
        }
    }
}

var test1 = Test();
test1.something();

var test2 = Test();
test2.something();

Both test1 and test2 print a reference to the Window object instead of the module itself.

Any idea how to change it so that I have a valid this inside the module?

Upvotes: 2

Views: 81

Answers (3)

Paul D. Waite
Paul D. Waite

Reputation: 98786

I think you're confusing the JavaScript module pattern with JavaScript constructor functions.

JavaScript constructor functions

If you write a function and call it with the new keyword in front of it, then that function is called as a constructor function.

It will automatically return a new object, that you can refer to within the constructor function using the this keyword.

var Test = function() {
    var that = this;

    this.something = function () {
        console.info(that);
        console.info(this);
    };
}

var test1 = new Test();
test1.something();

You can return your own object instead, but you wouldn't normally do that in a constructor, you'd just use this instead:

var Test = function() {
    var that = this;

    return {
        something: function () {
            console.info(that);
            console.info(this);
        }
    };
}

var test1 = new Test();
test1.something();

If you don't call it with the new keyword in front of it, then it's called like a regular function, meaning any references to this inside of it refer to the object of which the function is a property (which, in the absence of anything else, will be the global object, which in web browsers is window).

var geoff = {
    Test: function () {
        var that = this;

        return {
            something: function () {
                console.info(that);
            }
        };
    }
};

var test2 = geoff.Test();
var test3 = Test();

Note: with constructor functions, you'd normally define methods on their prototype object, so that the methods don't get unnecessarily redefined for each object you create using the constructor function:

var Test = function() {
    this.else = "Something Else"
}
Test.prototype.something = function () {
    console.info(this);       
}
Test.prototype.somethingElse = function () {
    console.info(this.else);       
}

var test4 = new Test();
test1.somethingElse() // Logs "Something Else"

(Note that if you return your own object from the constructor function as we mentioned above, then you won't be able to access methods on the prototype object any more.)

Also note that each time you call a constructor function, it returns a new object. You can pass parameters into a constructor function (just like you can with any other function) and use them to customise the object returned:

var Test = function(else) {
    this.else = else;
}
Test.prototype.somethingElse = function () {
    console.info(this.else);       
}

var test1 = new Test("Something else");
var test2 = new Test("Something else again");

test1.somethingElse(); // Logs "Something else"
test2.somethingElse(); // Logs "Something else again"

Upvotes: 1

SDC
SDC

Reputation: 14222

The problem you have is because this refers to an object, but Test() isn't an object; it's just a function. The object that owns Test() is the Window object (because Test is in the global scope), so therefore that's what you get back when you reference this from within Test().

You may want to try something like this:

var testObj = {
    Test : function() {
        var that = this;
            return {
            something: function() {
                console.info(that);
            }
        }
    }
}

Now you can call testObj.Test(); and you'll get a reference back to the testObj object.

Hope that clarifies things a bit.

Upvotes: 0

paulslater19
paulslater19

Reputation: 5917

If you did

var test1 = new Test()

You could then do

test1.something(); 

An alternative module structure would be to do something like this:

var myModule = function () {
    var obj = {};
    obj.something = function () { 
         return console.log(obj);
    };
    obj.something2 = function () {
         return console.log(obj === this); // true
    };
    return obj;
};
var test = myModule();
test.something();
test.something2();

Hope this helps

Upvotes: 3

Related Questions