Here's the minimum you need to know, to understand how
this is evaluated. Every function in your program has access to
this and its value depends on the function's invocation. There are 4 different cases:
- Method invocation
- Function invocation
- Construction invocation
- Apply invocation
Method invocation
You are probably aware that a method is just a function that is a property of an object. When evaluated inside a method,
this has the value of the object holding that method. Quick example:
var foo = {
value: 0,
increment: function () {
this.value += 1;
}
}
foo.increment();
console.log(foo.value); // 1
foo.increment();
console.log(foo.value); // 2
this binding to the calling object is done at invocation time, which allows reuse of functions. For instance:
function foo() {
this.value += 1;
}
var a = {
value: 0,
inc: foo
}
var b = {
value: 10,
inc: foo
}
a.inc();
a.inc();
b.inc();
console.log(a.value); // 2
console.log(b.value); // 11
Function invocation
When a function is not invoked as a method,
this is bound to the global object
window (or
document).
For instance:
var a = 2;
function foo() { console.log(this.a);}
foo(); // 2
Beware that
this isn't bound to the scope of the outer function. What does that mean? Take a look at this code:
var value = 100;
var myObject = {
value: 0,
myMethod: function () {
function foo() {
this.value += 1;
console.log(this.value);
}
foo();
}
}
myObject.myMethod(); // 101
Why does this code output 101 and not 1? Because the moment foo() is invoked, it's not invoked as a method but as a function, so this is bound to the global object and not myObject. To avoid this problem, here's a very common idiom in JavaScript:
var value = 100;
var myObject = {
value: 0,
myMethod: function () {
var self = this;
function foo() {
self.value += 1;
console.log(self.value);
}
foo();
}
}
myObject.myMethod(); // 1
self is not a special variable, so it's not treated any differently than others. Unlike
this, it's perfectly okay to define
self in the outer scope and the function
foo will have no problem fetching
self outside.
(I hope this gives a specific answer to your question)
Constructor invocation
A constructor is a function called after the
new prefix. These functions create new objects, and
this is bound to the object being created.
function foo () {
this.value = 0;
}
var a = new foo();
console.log(a.value); // 0
Apply invocation
apply() is a function that is familiar to the programmers working in a Functional Programming style. It's a function that allows to construct a list of arguments dynamically and apply another function to them.
You can find something similar in most modern dynamic languages. In JavaScript, apply() is a method to all the other functions. Remember that in JS, everything is an object, even a function, and every object can have methods. It takes 2 arguments:
- The value of this
- An array of parameters
As you can see, in this type of invocation, the binding of
this is very explicit and you won't have to worry about it. Here's how you can use it:
function sum(a, b) {
return a + b;
}
console.log(sum.apply(null, [4, 6])); // 10
And here's how you can take advantage of
this:
var myObject = {
value: 10,
}
function foo () {
return this.value + 1;
}
console.log(foo.apply(myObject, [])); // 11
Usually, you won'd be dealing with the apply invocation pattern very often.
More info
For a more detailed explanation of
this, as well as solid (and opinionated) insight into JavaScript, I strongly recommend
JavaScript the Good Parts by Douglas Crockford.