# The this Keyword

At some point you will write a method on an object, call it directly and it works fine, then pass it somewhere as a callback and it completely falls apart. [`this.name`](http://this.name) comes back `undefined`. The code looks exactly the same to you. The error message is no help at all.

That is `this` doing something you did not expect, because nobody explained the one idea that makes all of its behavior obvious. This post is built around that idea. Everything else follows from it.

## **What** `this` **Represents**

`this` is the object that called the function. Not where the function was written, not where it lives in the file. Who called it, right now, at this moment.

Think of a customer service line. When someone calls in, the rep picks up and sees the caller's name on screen. That display changes every time a different person rings. The phone line is the function. The name on the display is `this`.

Here is the simplest version of that in code:

```javascript
function greet() {
  console.log("Hello, I am " + this.name);
}

const user  = { name: "Rohan", greet };
const admin = { name: "Priya", greet };

user.greet();   // user called it: this = user
admin.greet();  // admin called it: this = admin

// OUTPUT:
// Hello, I am Rohan
// Hello, I am Priya
```

One function, written once. The dot before the method call is your clue every time: whatever is on the left of that dot when the function runs is `this`. Keep that in mind as you read the rest of this post.

![](https://cdn.hashnode.com/uploads/covers/678b775e773554ab7117f20a/a106176d-0b7a-4190-9f16-17ff15b33af2.png align="center")

## `this` **In The Global Context**

Before any functions or objects, there is already a `this`. At the very top of a script, outside everything else, it points to the global object. In a browser that is `window`.

```javascript
// Browser
console.log(this);            // Window {…}
console.log(this === window); // true
```

In Node.js the story is slightly different. At the top of a CommonJS file, `this` is the module's `exports` object, not Node's global. It looks like an empty object by default because nothing has been exported yet.

```javascript
// Node.JS
console.log(this);                   // {}
console.log(this === global);         // false
console.log(this === module.exports); // true
```

You will almost never use the global `this` on purpose. What matters here is knowing it exists so you are not confused when it shows up unexpectedly in the console or in an error message.

## `this` **Inside Objects**

When a function is called as a method of an object, `this` is that object. This is the case that feels the most natural and the one that matches what beginners usually expect. The object called the method, so the object is `this`.

```javascript
const player = {
  name:  "Rohan",
  score: 1400,
  showScore() {
    console.log(this.name + " has " + this.score + " points");
  }
};

player.showScore();  // player is on the left: this = player

// OUTPUT:
// Rohan has 1400 points
```

Swap the caller, swap `this`. The same function attached to two different objects gives two different results:

```javascript
const playerOne = { name: "Rohan", score: 1400 };
const playerTwo = { name: "Divya", score: 2100 };

function showScore() {
  console.log(this.name + " has " + this.score + " points");
}

playerOne.show = showScore;
playerTwo.show = showScore;

playerOne.show();  // this = playerOne
playerTwo.show();  // this = playerTwo

// OUTPUT:
// Rohan has 1400 points
// Divya has 2100 points
```

### The Lost `this`

When you copy a method into a variable and call it, `this` is gone.

```javascript
const player = {
  name: "Rohan",
  greet() {
    console.log("Hi, I am " + this.name);
  }
};

player.greet();          // `this` doesn't get lost

const fn = player.greet;  // just the function, no object
fn();                     // `this` gets lost

// OUTPUT:
// Hi, I am Rohan
// Hi, I am undefined
```

![](https://cdn.hashnode.com/uploads/covers/678b775e773554ab7117f20a/edc4ae0f-f2e7-4693-8d3e-1131ad165148.png align="center")

Passing a method as a callback is the same problem. `setTimeout(player.greet, 1000)` hands over the function with no object. When it runs a second later, `this` is not `player`. This shows up constantly in real code.

## `this` **Inside Regular Functions**

When a plain function is called with nothing on the left of the dot, `this` defaults to the global object. In strict mode it becomes `undefined` instead, which is actually safer because it fails loudly.

```javascript
// Non-strict. this defaults to Window
function whoAmI() {
  console.log(this);
}

whoAmI(); // Window {…} in the browser

// Strict mode. this becomes undefined
"use strict";

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

whoAmIStrict(); // undefined
```

ES modules are strict by default. If your files use `import` and `export`, strict mode is already on. Most modern JavaScript projects run in modules, so you already have this without thinking about it.

### **Nested Functions Lose** `this`

A regular function written inside a method does not inherit the method's `this`. It resets. The inner function is called as a plain function, so it gets the global default. Proximity in code has no effect; only the call site matters.

```javascript
const game = {
  title: "Space Run",
  start() {
    console.log(this.title); // "Space Run". this = game

    function inner() {
      console.log(this.title); // undefined. this reset to Window
    }

    inner(); // called alone. no object on the left
  }
};

game.start();

// OUTPUT:
// Space Run
// undefined
```

The fix for this is arrow functions, which do not reset `this`.

## **How the Calling Context Changes** `this`

Because `this` is set at call time, you can control it. JavaScript gives you three methods for this: `call`, `apply`, and `bind`.

### `call()` **and** `apply()`

Both invoke the function immediately and let you specify the object to use as `this`. The difference is just how you pass other arguments. `call` takes them one by one. `apply` takes an array.

```javascript
function introduce(city, sport) {
  console.log(this.name + " is from " + city + " and plays " + sport);
}

const maya = { name: "Maya" };
const leo  = { name: "Leo"  };

introduce.call(maya,  "Mumbai",  "cricket");     // args one by one
introduce.call(leo,   "Lisbon",  "football");
introduce.apply(maya, ["Mumbai", "cricket"]);   // args as array

// OUTPUT
// Maya is from Mumbai and plays cricket
// Leo is from Lisbon and plays football
// Maya is from Mumbai and plays cricket
```

### `bind()`

`bind` does not call the function. It returns a new copy with `this` permanently locked. That copy can be stored, passed around, and called later. It will always have the same `this`. This is the direct fix for the lost-this trap.

```javascript
const player = {
  name: "Rohan",
  greet() {
    console.log("Hi, I am " + this.name);
  }
};

// Without bind, this is lost when passed as a callback
setTimeout(player.greet, 0);

// With bind, this is locked to player permanently
setTimeout(player.greet.bind(player), 0);

// OUTPUT:
// Hi, I am undefined
// Hi, I am Rohan
```

| Method | Calls immediately | Args format | Returns |
| --- | --- | --- | --- |
| **call(obj, a, b)** | Yes | one by one | result of the function |
| **apply(obj, \[a, b\])** | Yes | as an array | result of the function |
| **bind(obj, a, b)** | No | one by one | a new bound function |

## **Arrow Functions and** `this`

Arrow functions do not have their own `this`. They look at the code around them at the time they were written and borrow whatever `this` was in that scope. That value never changes, regardless of how the arrow function gets called later.

This is exactly what fixes the nested function problem:

```javascript
const game = {
  title: "Space Run",
  start() {
    // Regular function: this resets to Window inside here
    function inner() {
      console.log("regular: " + this.title);
    }

    // Arrow: borrows this from start(), which is game
    const innerArrow = () => {
      console.log("arrow: " + this.title);
    };

    inner();       
    innerArrow();  
  }
};

game.start();

// OUTPUT:
// regular: undefined
// arrow: Space Run
```

### **Where Arrow Functions Go Wrong**

Arrow functions work great inside methods. Used as a method directly on an object, they break. The surrounding scope at write time is the global scope, so that is what gets borrowed.

```javascript
// Arrow as method: breaks
const player = {
  name: "Rohan",
  greetArrow: () => {
    // borrows global scope
    console.log(this.name);
  }
};

player.greetArrow();
// undefined

// Regular as method: works
const player = {
  name: "Rohan",
  greetRegular() {
    // set at call time = player
    console.log(this.name);
  }
};

player.greetRegular();
// Rohan
```

![](https://cdn.hashnode.com/uploads/covers/678b775e773554ab7117f20a/8077df7f-5787-46ab-b77f-a78d983b5f71.png align="center")

The practical rule: write methods on objects and classes with regular function syntax. Write callbacks inside those methods with arrow functions. That combination gives you the right `this` in both places without needing to think too hard about it.

## **All the Contexts at Once**

Every case in this post comes from the same question: who is calling the function right now? Here is how each calling pattern maps to a result, and how to recognise which one you are looking at:

![](https://cdn.hashnode.com/uploads/covers/678b775e773554ab7117f20a/15a65f7c-f923-4475-ad07-745196e08204.png align="center")

When you are unsure which case applies, ask the same question every time: what is on the left of the dot when this function is called? If there is an object, that is `this`. If there is nothing, you are in the plain function case. If you used `call`, `apply`, or `bind`, you set it yourself. Arrow functions are the only exception, they ignore the call site entirely and use whatever was in scope when they were written.

Most of the bugs you will encounter are just the extracted-method case. A function that worked on an object, passed somewhere as a callback, lost its caller. `bind` fixes it. Arrow callbacks inside methods fix it too. Once you see what is happening, the fix is never complicated.

**REFERENCES:**

*   [MDN: this](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)
    
*   [JavaScript.info](http://JavaScript.info)[: Object methods and this](https://javascript.info/object-methods)
    
*   [MDN: Function.prototype.bind()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)
    
*   [MDN: Arrow function expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
