Save this for Later

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...

blog comments powered by Disqus