The this
variable in Javascript is sometimes a source of confusion and frustration for newcomers to the language. If you don't know exactly how binding works, you are never quite sure what this
refers to.
A commonly made mistake is when you need to create an inlined function within another function. This is commonly needed to make an ajax call, for example
$('#myButton').click(function(){
$.get(url, function(data){
render(data)
$(this).hide() // try to hide the button
})
})
Here, the attempt to hide the button will fail, because while this
did refer to the button within the outer function, it no longer refers to it within the inner function. The solution to this problem is to save this
into a variable while still within the scope of the outer function
$('#myButton').click(function(){
var button = this
$.get(url, function(data){
render(data)
$(button).hide() // now, hide the button
})
})
Great! We are done, right?
Not so fast! Don't you want to know how binding works in its entirety? Allllllllrighty then.
What in the H is this
?
Let's say we have an object bob
that has a name
property
var bob = {name: 'Bob'}
Let's say you then attach a function to it, like so
bob.greet = function(){
console.log("Hello, I am " + this.name)
}
Now, binding will occur - binding this
to bob
- whenever you call the function through the object bob
bob.greet() // prints "Hello, I am Bob"
which is how the greet
function was able to access bob
's name
property. this
is also called the context, which I will start referring to it as.
Auto-bind to window
If you call the function all by itself, its context will instead bind to the global window
object
var greet = bob.greet
greet() // prints "Hello, I am "
window
does have a name
property, however most of the time it contains the empty string, which explains why calling greet()
prints out "Hello, I am "
.
Changing the Context with call
and apply
The two ways of calling a function shown above allow you to set the context to either the object that the function is attached to, or the window
object. But, Javascript also allows you to set the context to any other object you want, using one of the two methods: call
and apply
. This is where it gets interesting.
var jane = {name: 'Jane'}
greet.call(jane) // prints "Hello, I am Jane"
greet.apply(jane) // prints "Hello, I am Jane"
The call
and apply
methods are available for all Javascript functions. Both of them execute the function, taking the context as their first argument.
The difference between the two is in how they receive regular arguments to the function. So for example, if our greet
function also took a normal parameter
function greet(other){
console.log('Hello ' + other + ', I am ' + this.name)
}
To pass the other
parameter to call()
, we must list it as the second parameter, like so (let's set it to bob
)
greet.call(jane, bob) // prints "Hello Bob, I am Jane"
But with apply
we would instead wrap the argument list with an array - in this case just the element bob
- and pass the array as the second parameter
greet.apply(jane, [bob])
This is real cool! call
and apply
give JS programmers a great deal of flexibility in how they can design their libraries.
But still, how do you know what this
is?
Sometimes, as is the case with our jQuery example
$('#myButton').click(function(){
var button = this
$.get(url, function(data){
render(data)
$(button).hide() // now, hide the button
})
})
you can't tell what the context is going to be bound to just by looking at the code. When you pass a function into a library, like jQuery, you need to know what the library will bind the context to - this is part of the contract between the API and its user: so we have to read the docs.
In jQuery, event handlers(look under "Event Handlers" are always bound to the DOM element that triggered the event - this is how we know this
will be bound to the element #myButton
within the click
handler.
As for the Ajax handler for $.get
, I actually could not find any documentation on the jQuery site as to what its context is bound to, however, upon runtime inspection, it appears to be a hash of the Ajax parameters that are used for the request. In any case, it doesn't help us, and so we resort to saving the context as a variable in the scope of the click handler when we still can.
Conclusion
Always be sure you know what the this
is when you need to use it. Don't just assume. Because when you assume...