Javascript Methods, Functions, and Constructors
One of the most confusing parts of Javascript (for me at least) is keeping track of what this
refers to.
I always end up referring back my copy of Javascript: The Good Parts, which, by the way, I think is a must read for any web developer.
Just recently, I went back and refreshed my memory about this
, methods, functions and constructors and I decided to jot down some notes here, hope this is helpful.
Four Ways to invoke Functions
In Javascript, these are the 4 contexts in which functions can be evaluated:
- method invocation
- function invocation
- constructor invocation
- apply invocation
Method invocation
When a function is stored as a property of an object, it's referred to as a "method" and this
is bound to the object. Here's an example of a method named setName
:
var person = {name: "Harry",
setName: function(name) {
// `this` refers to object
this.name = name;
}
}
And here's how the setName
method could be called:
> person.name
"Harry"
> person.setName("Hermione");
> person.name
"Hermione"
Function Invocation
A function is considered a "method" when it's defined as a member of an object. But when a function is defined anywhere outside the context of an object, the this
keyword is bound to the global object.
Here's an example of a function:
var myFunction = function() {
// `this` bound to global object
this.isnt_very_useful = "hello";
};
Things get really confusing when you define a function inside a method.
// 'setName' is a method because it's tacked onto an object
person.setName = function(name) {
// 'this' refers to the person object. Here's a trick so
// that we can reference the thing that 'this' points to
// here later.
var that = this;
// here's a function inside the 'setName' method
var setDefaultName = function() {
// `this` refers to global object!
this.name = "this isn't what we want!";
// Good thing that we bound the value of 'this' from the 'setName'
// method to a new variable named 'that' earlier, because now we
// can use 'that' to access the thing that you probably think that
// 'this' should actually refer to!
that.name = "Draco";
}
if (this.name == undefined)
setDefaultName();
};
Confusing, eh?! Just remember that this
inside functions always refers to the global object.
Here's some proof that the that
trick worked:
> person.setName();
> person.name
"Draco"
And remember when we assigned 'this' inside the 'setDefaultName' function? Check this out:
> this.name
"this isn't what we want!"
Didn't see that coming, did ya?!Constructor Invocation
When a function is called with the new
prefix, it's referred to as a constructor. Calling functions using new
creates a new object. Inside constructors, the this
keyword is assigned to the new object.
The confusing part here is that if you accidentally forget to use new
, then unexpected things happen. I never use constructor invocation, it's too easy to forget new
. But here's an example:
// Here's a constructor
var Person = function (name) {
this.name = name;
};
// And here's a method on our Person Class
Person.prototype.getName = function() { return this.name };
Here's an example to prove this
works the way I think it does inside constructor functions:
> var person = new Person("Dave");
> person.getName();
"Dave"
> var person = Person("Dave");
> person.getName();
Uncaught TypeError: Cannot read property 'getName' of undefined
See the scary error message when I forgot to use new
?!
Apply Invocation
Finally, for full control, you can use apply
to manually evaluate functions. The apply
function takes 2 arguments. The first argument controls what this
will be bound to. The second argument is an array of args to pass to the function.
Let's define a cat
object:
var cat = {"name": "shubie"};
Now, notice that our cat object doesn't have a getName
method defined. But check this out! We can reuse the getName
method from the Person object above on the cat
like so:
> Person.prototype.getName.apply(cat);
"shubie"
By passing the cat
object as the first argument to apply
, we made sure that apply
treats cat
as this
when evaluating Person.prototype.getName
. Pretty crazy, right?
Summary
Understanding the 4 contexts in which functions can be called in javascript, will help you to understand the this
keyword.
Also, like I mentioned, Javascript: The Good Parts, does a great job of explaining all this and more. Mozilla has nice documentation here as well.