Explain the `this` keyword in JavaScript

HighIntermediateJavascript
Quick Answer

The value of this depends on call site, strict mode, and arrow functions. The real debug problem is detached methods, callback context loss, and object methods that stop pointing at the receiver you expected.

Answer

The Core Idea

The value of this is determined by how a function is called, not by where it is written. This becomes a real debug issue when a method is detached, passed as a callback, or mixed with arrow functions and strict mode.

So the useful mental model is not 'owner of the function' but 'receiver at call time.'

Call Type

Value of this

Example

Global / Default

In browsers → window, in strict mode → undefined

console.log(this)

Object method

The object before the dot

user.sayHi()this === user

Constructor

The newly created instance

new Person()

Explicit binding

Set manually using call, apply, or bind

fn.call(obj)this === obj

Arrow function

Does not bind this; inherits it from its outer scope

() => this inside an object → outer this

How `this` changes based on how the function is called.
JAVASCRIPT
// Example 1: Default binding
function show() {
  console.log(this);
}
show(); // window (or undefined in strict mode)
                  
JAVASCRIPT
// Example 2: Method call
const user = {
  name: 'Mia',
  greet() {
    console.log('Hi, ' + this.name);
  }
};
user.greet(); // 'Hi, Mia'
                  
JAVASCRIPT
// Example 3: Detached method loses context
const greetFn = user.greet;
greetFn(); // undefined or 'Hi, undefined' — this is lost
                  

Fixing Lost Context

You can control or preserve this explicitly using:

  • call() / apply() → call immediately
  • bind() → return a new function with fixed this
JAVASCRIPT
const boundGreet = user.greet.bind(user);
boundGreet(); // 'Hi, Mia'
                  

Arrow Functions

Arrow functions don’t have their own this. They inherit it from the surrounding scope. Great for callbacks that need lexical this.

JAVASCRIPT
function Timer() {
  this.seconds = 0;
  setInterval(() => {
    this.seconds++;
    console.log(this.seconds);
  }, 1000);
}
new Timer(); // works fine

// But using a normal function would break:
// setInterval(function() { this.seconds++ }, 1000); // this = undefined
                  

Common Pitfalls

  • Forgetting newthis becomes global (or undefined in strict mode)
  • Losing context when passing methods as callbacks
  • Misusing arrow functions in class methods (they can’t be rebound)

Practical scenario
A class method passed as a callback loses this, breaking access to instance state.

Common pitfalls

  • Forgetting to bind methods in constructors.
  • Using arrow functions and expecting dynamic this.
  • Calling functions without a receiver in strict mode.
Trade-off or test tip
Binding is explicit but creates new functions. Test with call/apply/bind and verify this values.

Still so complicated?

Think of this as the person holding the phone 📱 — not the number you dialed. The number (function) stays the same, but who picks up (the object that calls it) decides what this will be.

Summary
  • this depends on the call site, not where the function is defined.
  • Arrow functions don’t have their own this.
  • call, apply, and bind let you control this explicitly.
  • new creates a new object and binds this to it.
Similar questions
Guides
Preparing for interviews?

Use the relevant interview-question hub first, then move into a concrete study plan before targeted company sets.