Recently I stumbled about this post about The complete elimination and eradication of JavaScript’s this.

To give you a TL;DR: The author states that almost no JavaScript developer understands this , that it is a terrible concept, and introduces a library that allows developers to avoid using this in many circumstances. So, we had a twitter discussion with pretty opposing standpoints: I think this in JavaScript is quite simple, versatile and really useful.

But in the next days, it got me thinking …

Yeah, I’ve met my share of developers that I had to explain to how this works. But I don’t believe that introducing a new concept to avoid the use of this altogether is a good solution. It’s like avoiding olives all your life because you didn’t like them at the age of 13. When you are 55, you will try some by accident, they will be delicious and you will mourn the last 30 years of your life that could have been so much better with olives (or this , for that matter).

So, let’s actually talk about this

Before we go deeper, I’ll give you a simple rule of thumb:

this in a function is, in this order

what the function was explicitly bound to (using bind or a similar construct)

or a similar construct) what the function was explicitly called with (using call or apply )

or ) what was left of the dot at the moment of execution

something else like a global context that you should not rely on

„Left of the dot“? You’re trolling me right now!

Yeah, of course, that one rule seems the weirdest, but I think it’s the best way to put it and make it easy to understand. Let us start with two little test objects:



let a = { about: "This is object a", testFunction: function() { console.log(this); } }; let b = { about: "This is object b" };

a.testFunction(); // Object { about: "This is object a", testFunction: testFunction() }

a.testFunction

b.testFunction

b.testFunction = a.testFunction; b.testFunction(); // Object { about: "This is object b", testFunction: testFunction() }

testFunction

a

this

b.testFunction

b

So, let’s run something on it:Okay, we expected that. Now, what if we assignto b and callAlthough we initially definedon our objectwhen callingnow is

So now you might get what I was meaning by ‚left of the dot‘. You could also say ‚called on‘, but I like to think about this as the 0th argument to a function. That way, it is very consistent with the signature of Function.prototype.call , which we’ll talk about later.

„Something else“? So it is all hogwash!

Yeah, no. Let’s continue with our example above and see what it does in different contexts, when there is nothing left of the dot:



let a = { about: "This is object a", testFunction: function() { console.log(this); } }; let c = a.testFunction; c();

this

window

global

strict mode

let a = { about: "This is object a", testFunction: function() { 'use strict'; console.log(this); } }; let c = a.testFunction; c();

undefined

When we execute this code in a browser,points to theobject. Executed in node, we get theobject. In, it behaves a little differently:Running it now in the browser or in node, we get thevalue.

So yeah, it is predictable and defined. But my point is: if you want to access window or global respectively, just access window or global . Doing that access with this will help no-one understand your code. So, don’t do it and treat this in that context just as „something else“ and never think about it again.

But when I’m writing this.foo as a property in React/JSX, it does not set this to the value left of the point. What’s going on there?

Notice that above, I said ‚left of the dot at the moment of execution‘? What you are doing here is passing that function for it to be executed later. It will be stuffed into a variable, and just like in the last chapter where we assigned c = a.testFunction , the ‚left of the dot‘ context will be lost before it is finally executed.

This is why you need to bind functions you pass in jsx, or use the fat arrow notation.

Explicitly specifiying this at runtime: call and apply

You can also specify at runtime what this will be on method execution. Look at this example:



console.log(b.testFunction.call(a)); // Object { about: "This is object a", testFunction: testFunction() }

stored

b

a

apply

So while the function isin our object, it is called on. Alternatively, you cann use themethod.

call and apply are pretty similar, but differ when you want to pass additional arguments to the function. The following two method calls would be identical:



c.call(newThis, firstArgument, secondArgument, thirdArgument); c.apply(newThis, [firstArgument, secondArgument, thirdArgument]);

this

Explicitly binding this: bind and fat arrow functions

Seeing the signature of call, you might also understand why I like to think ofas the „0th argument“ of a function.

So what if you have no control over how and when a method is called, but want complete control over what this is when it is executed? Then you can bind a method. Look at this example:



b.testFunction = c.bind(a); b.testFunction(); // Object { about: "This is object a", testFunction: testFunction() }

testFunction

b

a

a

So even though you are callingon, it was bound toand so, this will always point to

Simplified, bind wraps your function in another function that always calls your function with the this that it was bound to.

While this is great, keep in mind that you cannot change what a function is bound to once it was bound once because you would only change what the wrapping function is bound to, not what the wrapped function is bound to. Because of the same reason, you cannot use apply or call to change this any more.

Fat Arrow Function

Now, let’s talk about a fat arrow function in that context. The following two statements are roughly equivalent:



let y = (function(){ console.log(this); }).bind(this); let z = () => { console.log(this) };

this

So an arrow function automatically binds to the value ofat the exact moment the method is defined. This is called lexical binding or static binding.

That property makes it so useful in every situation where a function is passed as a value (in JSX for example), because this will be exactly what it is while you write it.

Phew. That was a lot of information. And you call that simple?

Yup. While there was a lot of information, just try to remember this even shorter version of my my rule of thumb from the top:

This is what was explicitly bound to, or what was specified at runtime, either by using call / apply or just by calling a function with something left of the dot.