# Understanding the this Keyword in JavaScript



`this` = most confusing JavaScript concept. What `this` refer to? Depend on who call function. Caller = `this`. Understand caller, understand `this`.

This about `this` keyword and how it change.

* * *

## What this Represents

`this` = reference to caller. Who call function? That who `this` is.

### Simple Definition

`this` = the object that calling the function. Not the function itself. The thing that call it.

### Real Analogy

Waiter in restaurant:

```
Customer say "I want coffee"
Waiter say "Who want coffee?"
Customer say "Me, I want coffee"

So "I" = the customer (the caller)
```

In JavaScript:

```javascript
user.greet()  // user calling greet()
              // So "this" inside greet = user
```

`this` = who call the method.

### Why this Matter

`this` let function know who calling it. Function can behave different for different callers.

```javascript
const user1 = {
  name: 'Alice',
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

const user2 = {
  name: 'Bob',
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

user1.greet();  // "Hello, I'm Alice"
                // this = user1

user2.greet();  // "Hello, I'm Bob"
                // this = user2
```

Same function logic. Different `this`. Different output.

* * *

## this in Global Context

In global scope, `this` = global object.

### Browser Global

In browser, global object = `window`.

```javascript
console.log(this);  // window (in browser)
console.log(this === window);  // true

console.log(this.innerHeight);  // window.innerHeight
```

Top level code run in window context. So `this` = window.

### Node.js Global

In Node.js, global object = `global` (or module context).

```javascript
console.log(this);  // {} (module context in Node.js)
                    // NOT global in strict module

console.log(global);  // global object
```

Node.js = different. But usually don't use `this` in global scope.

### Function in Global Scope

```javascript
function greet() {
  console.log(this);
}

greet();  // Browser: window
          // Node.js: global (in strict mode: undefined)
```

No caller = default caller = global object.

### Problem: Losing this

```javascript
const user = {
  name: 'Alice',
  greet() {
    console.log(this.name);
  }
};

const func = user.greet;  // Extract method
func();  // undefined (or error)

// Why?
// func() have no caller object
// So this = global or undefined
// global.name = undefined
```

When extract method = lose context = lose `this`.

* * *

## this Inside Objects

`this` = the object calling method.

### Method Call

Object call its own method. `this` = object.

```javascript
const user = {
  name: 'Alice',
  age: 25,
  
  greet() {
    console.log(`I'm ${this.name}`);
  },
  
  haveBirthday() {
    this.age++;
    console.log(`Now ${this.age}`);
  }
};

user.greet();         // this = user
                      // "I'm Alice"

user.haveBirthday();  // this = user
                      // Now 26
```

`user.greet()` = user calling greet = this = user.

### Accessing Object Properties

Method use `this` to access own properties.

```javascript
const car = {
  brand: 'Toyota',
  speed: 0,
  
  accelerate() {
    this.speed += 10;
    console.log(`${this.brand} speed: ${this.speed}`);
  }
};

car.accelerate();  // "Toyota speed: 10"
car.accelerate();  // "Toyota speed: 20"

console.log(car.speed);  // 20
```

`this.speed` refer to car's speed property.
`this.brand` refer to car's brand property.

### Multiple Objects, Same Method

```javascript
const person1 = {
  name: 'Alice',
  introduce() {
    console.log(`I'm ${this.name}`);
  }
};

const person2 = {
  name: 'Bob',
  introduce() {
    console.log(`I'm ${this.name}`);
  }
};

person1.introduce();  // "I'm Alice" (this = person1)
person2.introduce();  // "I'm Bob"   (this = person2)
```

Different objects, same method logic. `this` different.

### Nested Objects

```javascript
const company = {
  name: 'TechCorp',
  owner: {
    name: 'Alice',
    greet() {
      console.log(`I'm ${this.name}`);  // this = owner (not company)
    }
  }
};

company.owner.greet();  // "I'm Alice"
                        // this = owner object (immediate caller)
```

`this` = immediate caller. Not parent object.

* * *

## this Inside Functions

Function context different from object context.

### Regular Function Call

```javascript
function greet() {
  console.log(this);
}

greet();  // Browser: window
          // Node.js: undefined (strict mode) or global

// No object call it = default context
```

Function standalone = no object caller = `this` = global or undefined.

### Function with Caller

```javascript
const user = { name: 'Alice' };

function greet() {
  console.log(`Hi, I'm ${this.name}`);
}

// Call function with user context
greet.call(user);  // "Hi, I'm Alice"
                   // Force this = user
```

`.call()` = force who caller is.

### Method vs Function

```javascript
const user = {
  name: 'Alice',
  
  method() {
    console.log(this.name);  // this = user (method call)
  },
  
  getFunction() {
    function inner() {
      console.log(this.name);  // this = global/undefined (function call)
    }
    return inner;
  }
};

user.method();        // "Alice" (this = user)

const func = user.getFunction();
func();               // undefined (this = global)
```

Method = `this` = caller.
Nested function = `this` = global (lose context).

* * *

## How Calling Context Change this

`this` depend on how function called. Three way to call function.

### 1. Method Call: obj.func()

Object call function. `this` = object.

```javascript
const user = {
  name: 'Alice',
  greet() {
    console.log(`Hi, ${this.name}`);
  }
};

user.greet();  // this = user
```

### 2. Function Call: func()

Direct call. `this` = global (or undefined in strict).

```javascript
function greet() {
  console.log(this);
}

greet();  // this = window (browser) or undefined (strict mode)
```

### 3. Using .call() or .apply()

Explicitly set `this`.

```javascript
const user1 = { name: 'Alice' };
const user2 = { name: 'Bob' };

function greet() {
  console.log(`Hi, ${this.name}`);
}

greet.call(user1);   // this = user1 → "Hi, Alice"
greet.call(user2);   // this = user2 → "Hi, Bob"
```

`.call(obj)` = call function with `this` = obj.

### Difference Visualized

```
user.greet()
  │
  └─ user calling greet
     └─ this = user

greet()
  │
  └─ no one calling (function call)
     └─ this = global

greet.call(user)
  │
  └─ explicitly set caller
     └─ this = user
```

Same function. Different caller. Different `this`.

* * *

## Arrow Functions and this

Arrow function different from regular function. Arrow function = inherit `this` from outer scope.

### Regular Function

```javascript
const user = {
  name: 'Alice',
  
  greet() {
    function inner() {
      console.log(this);  // this = global (function call)
    }
    inner();
  }
};

user.greet();  // this inside inner = global (lose context)
```

Nested function = lose `this`.

### Arrow Function

```javascript
const user = {
  name: 'Alice',
  
  greet() {
    const inner = () => {
      console.log(this);  // this = user (inherit from greet)
    };
    inner();
  }
};

user.greet();  // this inside inner = user (keep context)
```

Arrow function = inherit `this` from parent scope.

### When Use Arrow vs Regular

```javascript
const user = {
  name: 'Alice',
  
  // Regular function = this = user
  greet() {
    console.log(this.name);  // "Alice"
  },
  
  // Arrow function = this inherit from outer
  introduce: () => {
    console.log(this.name);  // undefined (this = window/global)
  }
};

user.greet();      // "Alice" (use regular function in object)
user.introduce();  // undefined (arrow lose this context)
```

Rule:
- **Object method** = use regular function (get `this` = object)
- **Nested callback** = use arrow function (inherit `this`)

### Practical Example

```javascript
const button = {
  label: 'Click me',
  
  // ✗ Wrong - regular function lose this
  setupWrong() {
    document.getElementById('btn').addEventListener('click', function() {
      console.log(this.label);  // this = button element (wrong)
                                // not this button object
    });
  },
  
  // ✓ Right - arrow function keep this
  setupRight() {
    document.getElementById('btn').addEventListener('click', () => {
      console.log(this.label);  // this = button object (right)
                                // inherited from setupRight
    });
  }
};
```

Event listener = arrow function keep `this`.

* * *

## Common this Mistakes

### Mistake 1: Losing this in Callback

```javascript
const user = {
  name: 'Alice',
  
  loadData(callback) {
    setTimeout(callback, 1000);
  },
  
  fetch() {
    this.loadData(function() {
      console.log(this.name);  // this = undefined (function call)
    });
  }
};

user.fetch();  // undefined (wrong)
```

Fix with arrow function:

```javascript
user.fetch() {
  this.loadData(() => {
    console.log(this.name);  // this = user (right)
  });
}
```

### Mistake 2: Extracting Method Without Context

```javascript
const user = {
  name: 'Alice',
  greet() {
    console.log(this.name);
  }
};

const greet = user.greet;  // Extract method
greet();  // undefined (lose this)
```

Fix with .bind():

```javascript
const greet = user.greet.bind(user);  // Keep this = user
greet();  // "Alice" (right)
```

`.bind()` = permanently set `this`.

### Mistake 3: Confusing this in Constructor

```javascript
function User(name) {
  this.name = name;
  
  this.greet = function() {
    console.log(this.name);  // this = user instance
  };
}

const user = new User('Alice');
user.greet();  // "Alice" (this = user)
```

`new` = call function as constructor = `this` = new instance.

### Mistake 4: this in Arrow Function at Object Level

```javascript
// ✗ Wrong - arrow function at object level
const user = {
  name: 'Alice',
  
  greet: () => {
    console.log(this.name);  // this = window/global
                             // not user object
  }
};

user.greet();  // undefined (wrong)

// ✓ Right - regular function
const user = {
  name: 'Alice',
  
  greet() {
    console.log(this.name);  // this = user
  }
};

user.greet();  // "Alice" (right)
```

Object method = use regular function. Not arrow function.

### Mistake 5: Assuming this Same in Nested Function

```javascript
const user = {
  name: 'Alice',
  
  process() {
    console.log(this.name);  // "Alice" (this = user)
    
    function inner() {
      console.log(this.name);  // undefined (this = global)
    }
    
    inner();  // this change!
  }
};

user.process();  // "Alice" then undefined
```

Nested function = new context = `this` change.

* * *

## Methods to Control this

### 1. Using .call()

Call function with specific `this`.

```javascript
function greet(greeting) {
  console.log(`${greeting}, I'm ${this.name}`);
}

const user = { name: 'Alice' };

greet.call(user, 'Hi');  // "Hi, I'm Alice"
                         // this = user
```

`.call(thisArg, arg1, arg2, ...)` = set `this` and call.

### 2. Using .apply()

Like `.call()` but arguments as array.

```javascript
function greet(greeting, emoji) {
  console.log(`${greeting}, I'm ${this.name} ${emoji}`);
}

const user = { name: 'Alice' };

greet.apply(user, ['Hi', '👋']);  // "Hi, I'm Alice 👋"
                                   // this = user
```

`.apply(thisArg, [args])` = same as call, but array arguments.

### 3. Using .bind()

Create new function with locked `this`.

```javascript
function greet() {
  console.log(`Hi, ${this.name}`);
}

const user = { name: 'Alice' };

const boundGreet = greet.bind(user);  // Create new function

boundGreet();  // "Hi, Alice"
               // this permanently = user
```

`.bind()` = don't call immediately. Return new function.

`.call()` and `.apply()` = call immediately.
`.bind()` = return function, call later.

### Practical Use: Event Listener

```javascript
const user = {
  name: 'Alice',
  
  setupButton() {
    const button = document.getElementById('btn');
    
    // ✗ Lose this
    // button.addEventListener('click', this.onClick);
    
    // ✓ Keep this
    button.addEventListener('click', this.onClick.bind(this));
  },
  
  onClick() {
    console.log(`Clicked by ${this.name}`);
  }
};
```

`.bind(this)` = keep `this` in event listener.

* * *

## this in Different Contexts

### Global Scope

```javascript
console.log(this);  // Browser: window, Node.js: depends on module
```

### Inside Object Method

```javascript
const obj = {
  method() {
    console.log(this);  // this = obj
  }
};

obj.method();
```

### Inside Regular Function

```javascript
function func() {
  console.log(this);  // undefined (strict) or global (non-strict)
}

func();
```

### Inside Arrow Function

```javascript
const arrow = () => {
  console.log(this);  // this = outer scope's this
};
```

### Inside Constructor

```javascript
function Constructor() {
  console.log(this);  // this = new instance
}

new Constructor();
```

### Inside Class

```javascript
class MyClass {
  method() {
    console.log(this);  // this = instance
  }
}

const obj = new MyClass();
obj.method();
```

### Inside Class Arrow Method

```javascript
class MyClass {
  method = () => {
    console.log(this);  // this = instance (arrow method)
  }
}
```

* * *

## Practical Examples

### Example 1: User Object

```javascript
const user = {
  name: 'Alice',
  age: 25,
  
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  },
  
  birthday() {
    this.age++;
    console.log(`Happy birthday! Now ${this.age}`);
  },
  
  describe() {
    return `${this.name} is ${this.age} years old`;
  }
};

user.greet();      // "Hello, I'm Alice"
user.birthday();   // "Happy birthday! Now 26"
console.log(user.describe());  // "Alice is 26 years old"

// All use this = user
```

### Example 2: Button Handler

```javascript
const app = {
  count: 0,
  
  init() {
    document.getElementById('btn').addEventListener(
      'click',
      this.handleClick.bind(this)  // Keep this = app
    );
  },
  
  handleClick() {
    this.count++;
    console.log(`Clicked ${this.count} times`);
  }
};

app.init();
// Click button → "Clicked 1 times"
// Click button → "Clicked 2 times"
```

Without `.bind(this)` = this = button element (wrong).

### Example 3: Method Borrowing

```javascript
const user1 = { name: 'Alice' };
const user2 = { name: 'Bob' };

function greet() {
  console.log(`Hi, ${this.name}`);
}

greet.call(user1);   // "Hi, Alice"
greet.call(user2);   // "Hi, Bob"

// Same function, different this, different output
```

Use `.call()` to borrow function with different context.

### Example 4: Constructor Pattern

```javascript
function User(name, age) {
  this.name = name;
  this.age = age;
  
  this.greet = function() {
    console.log(`I'm ${this.name}`);
  };
}

const user1 = new User('Alice', 25);
const user2 = new User('Bob', 30);

user1.greet();  // "I'm Alice" (this = user1)
user2.greet();  // "I'm Bob"   (this = user2)
```

`new` = create instance, set `this` = instance.

### Example 5: React Class Component

```javascript
class Counter extends React.Component {
  constructor() {
    super();
    this.state = { count: 0 };
    
    // Bind to keep this = component
    this.handleClick = this.handleClick.bind(this);
  }
  
  handleClick() {
    this.setState({ count: this.state.count + 1 });
  }
  
  render() {
    return <button onClick={this.handleClick}>Count: {this.state.count}</button>;
  }
}
```

React = need bind or arrow function to keep `this`.

* * *

## this Cheat Sheet

```
WHO CALL IT?           this = WHAT?
═════════════════      ══════════════════════
obj.method()           obj (the caller object)

func()                 undefined (strict) or global (non-strict)

new Constructor()      new instance

func.call(obj)         obj (explicitly set)

func.bind(obj)()       obj (locked in new function)

inside arrow function  outer scope's this (inherit)

inside event           element (default) or bound object
listener

inside setTimeout()    global (unless arrow)
```

* * *

## Practice Assignment

**1. Object methods:**

```javascript
// Create user object with:
// - name, email properties
// - greet() method (use this.name)
// - getEmail() method (use this.email)
// Test each method
```

**2. Losing and finding this:**

```javascript
// Create object with method
// Extract method, call it (lose this)
// Fix using .bind()
// Verify this = object again
```

**3. Arrow vs regular:**

```javascript
// Create object method that:
// - Use regular function for this = object
// - Use arrow function inside (inherit this)
// Test both work correctly
```

**4. Event listener:**

```javascript
// Create button handler object
// Add click listener
// Use .bind(this) to keep context
// Verify this = object inside handler
```

**5. Constructor pattern:**

```javascript
// Create User constructor function
// Add method using this.name
// Create 2 instances
// Call method on each (different this each time)
```

* * *

## Quick Recap

*   **`this`** = reference to caller. Who call function? That who `this` is.
    
*   **Global context** = `this` = window (browser) or global (Node.js).
    
*   **Inside object method** = `this` = object calling method.
    
*   **Inside function (not method)** = `this` = global or undefined (strict).
    
*   **Caller determine `this`** = same function, different caller, different `this`.
    
*   **Arrow function** = inherit `this` from outer scope (don't create own).
    
*   **Regular function** = create own `this` (depend on caller).
    
*   **`.call(obj)`** = call function with `this` = obj (immediately).
    
*   **`.apply(obj, [args])`** = like call but arguments as array (immediately).
    
*   **`.bind(obj)`** = create new function with `this` = obj (not immediate).
    
*   **Nested function** = lose `this`. Use arrow function or `.bind()`.
    
*   **Object method** = use regular function (get `this` = object).
    
*   **Event listener** = use arrow or `.bind()` to keep `this`.
    
*   **Constructor** = `new` set `this` = new instance.
    
*   **Class method** = `this` = instance automatically.
    
*   **Arrow in object** = wrong. Lose `this` context.
    
*   **Remember** = `this` = who calling the function.

Master `this` = master JavaScript.

* * *

> If you enjoyed this article, check out my other blogs on this profile. Connect with me: [LinkedIn](https://linkedin.com/in/rajharsh03) | [GitHub](https://github.com/RajHarsh03) | [X (Twitter)](https://x.com/rajharsh03)
