ponyfoo.com

Where does this keyword come from?

Working on the latest chapter for my upcoming book on JavaScript Application Design, I’m writing about how scoping works. I want to share a particular code sample which I hope will bring some clarity to how this works. It’s not all dark magic, learning about this can be tremendously helpful to your development as a JavaScript programmer.

Improve this article
Nicolás Bevacqua
| 6 minute read | 2

Until you “get it”, this is probably how you feel about this.

chaos.gif
chaos.gif

It’s madness, right? In this brief article, I aim to demystify this.

How this works

If the method is invoked on an object, that object will be assigned to this.

var parent = {
    method: function () {
        console.log(this);
    }
};

parent.method();
// <- parent

Note that this behavior is very “fragile”, if you get a reference to method, and invoke that, then this won’t be parent anymore, but rather the window global object once again. This confuses most developers.

var parentless = parent.method;

parentless();
// <- Window

The bottom line is you should look at the call site to figure out whether the function is invoked as a property of an object or on its own. If its invoked as a property, then that property will become this, otherwise this will be assigned the value of the global object, or window. In this case, but under strict mode, this will be undefined instead.

In the case of constructor functions, this is assigned to the instance that’s being created, when using the new keyword.

function ThisClownCar () {
  console.log(this);
}

new ThisClownCar();
// <- ThisClownCar {}

Note that this behavior doesn’t have a way of telling a function is supposed to be used as a constructor function, and thus omitting the new keyword will result in this being the global object, like we saw in the parentless example.

ThisClownCar();
// <- Window

Tampering with this

The .call, .apply, and .bind methods are used to manipulate function invocation, helping us to define both the value for this, and the arguments provided to the function.

Function.prototype.call takes any number of arguments, the first one is assigned to this, and the rest are passed as arguments to the function that’s being invoked.

Array.prototype.slice.call([1, 2, 3], 1, 2)
// <- [2]

Function.prototype.apply behaves very similarly to .call, but it takes the arguments as a single array with every value, instead of any number of parameter values.

String.prototype.split.apply('13.12.02', ['.'])
// <- ['13', '12', '02']

Function.prototype.bind creates a special function which can be used to invoke the function it is called on. That function will always use the this argument passed to .bind, as well as being able to assign a few arguments, creating a curried version of the original function.

var arr = [1, 2];
var add = Array.prototype.push.bind(arr, 3);

// effectively the same as arr.push(3)
add();

// effectively the same as arr.push(3, 4)
add(4);

console.log(arr);
// <- [1, 2, 3, 3, 4]

Scoping this

In the next case, this will stay the same across the scope chain, this is the exception to the rule, and often leads to confusion among amateur developers.

function scoping () {
  console.log(this);

  return function () {
    console.log(this);
  };
}

scoping()();
// <- Window
// <- Window

A common work-around is to create a local variable which holds onto the reference to this, and isn’t shadowed in the child scope. The child scope shadows this, making it impossible to access a reference to the parent this directly.

function retaining () {
  var self = this;

  return function () {
    console.log(self);
  };
}

retaining()();
// <- Window

Unless you really want to use both the parent scope’s this, as well as the current value of this for some obscure reason, the method I prefer is to use the .bind function. This can be used to assign the parent this to the child scope.

function bound () {
  return function () {
    console.log(this);
  }.bind(this);
}

bound()();
// <- Window

Have you ever had any problems with this? How about this? Let me know if you think I’ve missed any other edge cases or elegant solutions.

Liked the article? Subscribe below to get an email when new articles come out! Also, follow @ponyfoo on Twitter and @ponyfoo on Facebook.
One-click unsubscribe, anytime. Learn more.

Comments (2)

André Alçada Padez wrote

I like your article, but have some remarks:

  • it is completely correct but I think it should be written targeting more novice javascript programmers; I wanted to show this to my team’s intern and seriously think he will be more confused after reading it.
  • when you’re explaining bind, call and apply, why use this as a reference to the window object, always? it makes it, again, confusing, for someone who doesn’t already know what they do and how they work to understand what’s going on, what is the difference between the first and the nested this.

Again, i don’t find any incorrections, it is very accurate. Just don’t see how this can help an inexperienced programmer and, if you’re writing for experienced programmers, we are usually aware of everything explained here.

Thanks

krishna kandula wrote

Thanks. First half of the article very helpful. Also Mozilla Developer Network has a wonderful article that can complement this.