In JavaScript, the "this" operator can refer to different things under different scenarios.

Typically in a method within a JavaScript "object", it refers to the current object.

But when used as a callback, it becomes a reference to the calling object.

I have found that this causes problems in code, because if you use a method within a JavaScript "object" as a callback function you can't tell whether "this" refers to the current "object" or whether "this" refers to the calling object.

Can someone clarify usage and best practices regarding how to get around this problem?

9 Answers
9

In JavaScript, "this" always refers to the object invoking the function that is being executed. So if the function is being used as an event handler, "this" will refer to the node that fired the event. But if you have an object and call a function on it like:

myObject.myFunction();

Then "this" inside myFunction will refer to myObject. Make sense?

To get around it you need to use closures... You can change your code as follows:

Do keep in mind that the statement "In JavaScript, "this" always refers to the object invoking the function that is being executed" is technically incorrect. There's four different contexts that this can have, depending on how a function is invoked.
–
Alan StormSep 17 '08 at 15:29

Quick advice on best practices before I babble on about the magic this variable. If you want OOP in Javascript that closely mirrors more traditional/classical inheritance patterns, pick a framework, learn its quirks, and don't try to get clever. If you want to get clever, learn javascript as a functional language, and avoid thinking about things like classes.

Which brings up one of the most important things to keep in mind about Javascript, and to repeat to yourself when it doesn't make sense. Javascript does not have classes. If something looks like a class, it's a clever trick. Javascript has objects (no derisive quotes needed) and functions. (that's not 100% accurate, functions are just objects, but it can sometimes be helpful to think of them as separate things)

The this variable is attached to functions. Whenever you invoke a function, this is given a certain value, depending on how you invoke the function. This is often called the invocation pattern.

There are four ways to invoke functions in javascript. You can invoke the function as a method, as a function, as a constructor, and with apply.

As a Method

A method is a function that's attached to an object

var foo = {};
foo.someMethod = function(){
alert(this);
}

When invoked as a method, this will be bound to the object the function/method is a part of. In this example, this will be bound to foo.

As A Function

If you have a stand alone function, the this variable will be bound to the "global" object, almost always the window object in the context of a browser.

var foo = function(){
alert(this);
}
foo();

This may be what's tripping you up, but don't feel bad. Many people consider this a bad design decision. Since a callback is invoked as a function and not as a method, that's why you're seeing what appears to be inconsistent behavior.

When invoked as a constructor, a new Object will be created, and this will be bound to that object. Again, if you have inner functions and they're used as callbacks, you'll be invoking them as functions, and this will be bound to the global object. Use that var that = this; trick/pattern.

Some people think the constructor/new keyword was a bone thrown to Java/traditional OOP programmers as a way to create something similar to classes.

With the Apply Method.

Finally, every function has a method (yes, functions are objects in Javascript) named apply. Apply lets you determine what the value of this will be, and also lets you pass in an array of arguments. Here's a useless example.

this corresponds to the context for the function call. For functions not called as part of an object (no . operator), this is the global context (window in web pages). For functions called as object methods (via the . operator), it's the object.

But, you can make it whatever you want. All functions have .call() and .apply() methods that can be used to invoke them with a custom context. So if i set up an object Chile like so:

In JavaScript, this doesn't refer to the current object, it refers to the current scope. That difference is very important. Often, the current scope is the current object, but sometimes (especially in the case of a closure or an anonymous callback function) the function is executed in the global scope.

There are a few ways to deal with this. If you have control over when your function is called, you can use the call() or apply() methods to execute the function in a specific scope. For example:

In your sample, you appear to be using the YUI Connection library, which accepts an object (not a function) as the third argument. The following example will make an asyncRequest() call that executes the callback in a specific scope:

You can also use Function.Apply(thisArg, argsArray)... Where thisArg determines the value of this inside your function...the second parameter is an optional arguments array that you can also pass to your function.

If you don't plan on using the second argument, don't pass anything to it. Internet Explorer will throw a TypeError at you if you pass null (or anything that is not an array) to function.apply()'s second argument...