Consider this:
window.onload = function () {
myObj.init();
};
var myObj = {
init: function () {
console.log("init: Let's call the callMe method...");
//callMe is not defined...
callMe();
//Works fine!
this.callMe();
},
callMe: function () {
console.log('callMe');
}
};
Since the init function gets called this way (myObj.init), I expect this
to be myObj in the init function. And if that is the case, why the callMe
function fails? How am I supposed to call the callMe
function without using the this context in the init body? (Actually, it's too annoying to call the object methods using this
over and over again through the functions. So what's the point of having a single object?)
I would like to know how can I fix this so that the callMe method gets called using the first invocation in the code above?
this
is never implicit in JavaScript as it is in some other languages. Although there are ways to do it, like this using the with
statement:
init: function () {
console.log("init: Let's call the callMe method...");
// Make `this` implicit (SEE BELOW, not recommended)
with (this) {
// Works
callMe();
}
},
...it's generally a bad idea. Douglas Crockford probably wrote one of the better descriptions of why it's a bad idea, which you can find here. Basically, using with
makes it nearly impossible to tell what the code's going to do (and slows the code down, if you do anything else in that with
statement that doesn't come from the this
object).
This isn't the only way that JavaScript's this
is not the same as it is in some other languages. In JavaScript, this
is defined entirely by how a function is called, not where the function is defined. When you do this.callMe()
(or the equivalent this["callMe"]()
, or of course foo.callMe()
, etc.), two things happen: The function reference is retrieved from the property, and the function is called in a special way to set this
to be the object that property came from. If you don't call a function through a property that way, the call doesn't set any particular this
value and you get the default (which is the global object; window
on browsers). It's the act of making the call that sets what this
is. I've explored this in depth in a couple of articles on my blog, here and here.
This (no pun) can be made even clearer if you look at JavaScript's call
and apply
functions, which are available on all function objects. If I do this:
callMe.call({});
...it'll call the callMe
function with a blank object ({}
) as this
.
So basically, just get used to typing this
. :-) It's still useful to have properties and methods associated with an object, even without the syntactic convenience (and confusion!) of an implicit this
.
You can also use the module pattern, which captures all private variables inside a closure, so you are free to use them without this
, as they're in the same scope. You then pick and choose which methods/variables you want to make public:
var myObj = (function () {
var init = function () {
callMe(); // This now works
};
var callMe = function () {
...
};
// Now choose your public methods (they can even be renamed):
return {
init: init, // Same name
callMyName: callMe // Different name
};
}) ();
Now:
myObj.init(); // Works
myObj.callMyName(); // Works
myObj.callMe(); // Error
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With