Last week we looked at this
, and how it can be assigned and manipulated. The example I gave showed that a function inside another function (or method) will resolve this
to the global object, and I used var self = this
to reference the intended object.
Reader n1k0 pointed out another solution: Function.prototype.call
:
Shape.prototype = {
move: function(x, y) {
this.x += x;
this.y += y;
function checkBounds() {
if (this.x > 100) {
console.error('Warning: Shape out of bounds');
}
}
checkBounds.call(this);
}
};
The call and apply Methods
In JS101: Object.create, I mentioned how Function.prototype.call
can be used to chain constructors. Let's take a deeper look at these methods of Function
.
The difference between the two is we generally use call
when we know what a function's arguments are, because they're supplied as arguments. Conversely, apply
expects an array of parameters:
Shape.prototype = {
move: function(x, y) {
this.x += x;
this.y += y;
function checkBounds(min, max) {
if (this.x < min || this.x > max) {
console.error('Warning: Shape out of bounds');
}
}
checkBounds.call(this, 0, 100);
checkBounds.apply(this, [0, 100]);
}
};
These methods have been around since ECMAScript 3rd Edition, and you'll see them used a lot. Take a look at the source for any popular JavaScript project and you'll find one of these methods being used:
Why are these methods so popular? Basically it comes down to functions being a first class citizen in JavaScript. I've been talking about the importance of objects for weeks, but learning how to manipulate functions is the key to mastering JavaScript.
JavaScript allows us to pass functions around, then execute them in different contexts by taking advantage of call
and apply
.
This is an example from the beginning of jQuery's documentation:
$('div.foo').click(function() {
$(this).slideUp();
});
Here, this
refers to the relevant DOM object. We've supplied our own callback, but this
points to something that makes sense within the context of jQuery's API.
Binding
In the comments for the previous post, Andres Descalzo pointed out that Function.prototype.bind can also be used to change this
. The bind
method of Function
was introduced in ECMAScript 5th Edition, and it returns a new function that's bound to a different this
:
Shape.prototype = {
move: function(x, y) {
this.x += x;
this.y += y;
function checkBounds(min, max) {
if (this.x < min || this.x > max) {
console.error('Warning: Shape out of bounds');
}
}
var checkBoundsThis = checkBounds.bind(this);
checkBoundsThis(0, 100);
}
};
Notice that a new variable has to be created for the newly bound function. The comment Andres posted uses an anonymous function to remove the extra variable:
Shape.prototype = {
move: function(x, y) {
this.x += x;
this.y += y;
var checkBounds = function(min, max) {
if (this.x < min || this.x > max) {
console.error('Warning: Shape out of bounds');
}
}.bind(this);
checkBounds(0, 100);
}
};
I like Mozilla's bind documentation, because it shows how some built-in methods like setTimeout
require less syntax when used with methods. The lesson here isn't really due to the design of setTimeout
but more general: using bind
is a convenient way to pass a method to another function.
Summary
When working with methods, the value of this
is important. By using the apply
, call
and bind
methods of Function
, we can:
- Change
this
inside a function, enabling flexible APIs to be created as demonstrated by popular projects like jQuery, Backbone.js, and Express - Reduce syntactical overhead when using functions inside methods, and passing methods to other functions -Chain calls to constructors (see JS101: Object.create)