Understanding `this` in Javascript
Tags: javascript, beginners, this
Published: 2021-08-02 12:46:48

## How did `this` all begin?

The one thing that seems to unify beginner javascript programmers more than anything else is their shared confusion about the concept of `this`.

Perhaps that's because `this` or `self` in other languages behaves differently than in javascript.

Look, the language was created in ten days. Some less than ideal decisions were probably made. It is what it is.

## `This` exists

I mean it. You can access `this` anywhere in a javascript program. At the outermost level? Sure!
```js
console.log(this);
```
Inside a function? Also, yes.
```js
function foo() {
  console.log(this);
}
```
What about constructors? Of course!
```js
function Bar(x, y) {
  this.x = x;
  this.y = y;
}
```
But see, **here lies the confusion**. It certainly _feels_ sensible to talk about `this` as a property on functions, constructors, and methods. But that's wrong.

`This` exists on its own! It's a property on function scopes!

## What's `this` scope thing?

You can think of function scopes (or **Function Environment Records** to be proper) as containers for variables. Each scope will contain a bunch of names of variables (and associated values).

From within any function scope you can:
1. access variables defined in that scope
2. access variables defined in any ancestor function scope

![scopes](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/27cw1ly1w9brhtr633i5.png)
 
At the outermost level is the global scope on which live such famous builtins as: `Math`, and `console`, and `Number` among others.

Notice how they are labeled **foo() scope** or **bar() scope** in the diagram and not **foo scope**, **bar scope**, etc.

That's because a scope is associated with function calls, not functions themselves. A new function scope is created for each function call. That's why you could do:
```js
function foo(x) {
  let bar = x;
}

foo(7);
foo(42);
``` and `bar` will be created two different times with two different values assigned to it.

Now look at the image again. You'll see `this` exists on each function scope. You don't need to declare it, it's added to the scope automatically.

## `This` once more

Here's a recap of what I just said:

![calls-scopes-this](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e7psmjhhuplng5l791b3.png)
 
Calls create function scopes. Those scopes create `this`. Ergo, by transitivity, **`this` is associated with function calls**.

Not functions. Not constructors. Calls!

## The rules of `this` language

In javascript, there are just two types of calls. The value of `this` depends on the type of call you make.

### 1. Function calls

Just plain old vanilla function calls.
```js
function foo() {
  console.log(this);
}

foo(); // Window
```
`This` gets set to the global `Window` object for these.

### 2. Method calls

Method calls are nothing special, just calls which have the form `<object>.<attribute>()`. For example:
```js
const foo = { 
  bar: function () {
    console.log(this);
  }
};
foo.bar();
``` For method calls, `this` gets set to the object from which the method was called. Again, functions don't matter* for `this`, just the calls.
```js
function foo() {
  console.log(this);
}

let x = { bar: foo };

foo(); // Window
x.bar(); // x
let baz = x.bar;
baz(); // Window
``` Even `baz` will print `Window`. It's not a method call, it doesn't follow the method call format!

That's pretty much all there is to it.........

........or is it?!

## I apologize for `this`

Remember how I told you `this` is all about function calls, not the functions themselves? Well, I lied.

Ok look, let me remind you once again: **They made javascript in 10 days!**

The `this` rules we've discussed above, they are a bit limiting. So there's **three*** ways you can override these rules.

###### _* don't you dare even mention apply_


### 1. `call`
The special `call` method on functions allows you to pass your own custom value of `this` to a function call (or the call's scope I should say).
```js
function foo() {
  console.log(this);
}

foo.call({ a: 42 }); // { a: 42 }
```
### 2. `bind`
`bind` is another builtin method on functions. Much like `call` it too allows you to pass a custom value for `this` to the function call. Except unlike `call`, `bind` doesn't immediately call the function. It instead returns a special 'bound' functions.
```js
function foo() {
  console.log(this);
}

let bar = foo.bind({ a: 42 });
foo(); // Window
bar(); // { a: 42 }
```
### 3. Arrow functions
Arrow functions are the third way to override the call rules for `this` described previously. Arrow functions capture the `this` from the function scope in which they are created.

![arrow-functions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qol2p9zarozgw76rkndu.png)
 
```js
function foo() {
  const bar = () => {
    console.log(this);
  };

  return bar;
}

let bar = foo.call({ a: 42 });
bar(); // { a: 42 }
```
So they're essentially the same as defining a normal function but then also binding it.
```js
// achieves the same effect
function foo() {
  const bar = (function () {
    console.log(this);
  }).bind(this);

  return bar;
}

let bar = foo.call({ a: 42 });
bar(); // { a: 42 }
```

## In summary

Yes, no pun in the heading `this` time (oops). The key takeaways are this:

In JS `this` is associated with the current function scope, and since function scopes are associated with functions calls -- `this` is associated with calls. Those are the rules but they can be overridden.

That is the reason why people are often confused when passing functions referencing `this` to callbacks. It's also why you were told to use arrow functions if you need to pass them to callbacks.

I too was confused about `this` for a long time. Instead of taking the more sensible approach of reading an article such as this one, I instead decided to implement my own javascript.

I wrote a subset of javascript. In that subset of javascript. If you want to go down that rabbit hole, then check out the repo:
https://github.com/BlueBlazin/thislang

If you want more posts on other javascript or computing related topics let me know on twitter:
https://twitter.com/suicuneblue