The "this" Keyword

Med

The `this` keyword refers to the object that is executing the current function. Its value is determined by HOW a function is called, not where it's defined. There are 4 main rules that determine what `this` refers to.

Interactive Visualization

CodeImplicit Binding
1const person = {
2 name: "Alice",
3 greet() {
4 console.log(this.name);
5 }
6};
7
8person.greet(); // "Alice"
Execution Context
this =
person
Rule: Object before dot = this
person.greet() is called - look at what's LEFT of the dot
1 / 2
Binding Priority: new → explicit (call/apply/bind) → implicit (dot) → default (global). Arrow functions inherit this lexically from enclosing scope.

Understanding The "this" Keyword

The this keyword in JavaScript is one of the most frequently misunderstood features of the language. Unlike most programming languages where this always refers to the current instance of a class, JavaScript determines the value of this dynamically based on how a function is called, not where it is defined. This distinction is the root cause of countless bugs and a favorite topic in JavaScript interviews.

There are four binding rules that determine what this refers to, applied in order of precedence. The highest priority is the new binding: when a function is called with the new keyword, this refers to the newly created object. Next is explicit binding, where you manually set this using call(), apply(), or bind(). The call and apply methods invoke the function immediately with a specified this value, while bind returns a new function with this permanently set. Third is implicit binding, which applies when a function is called as a method of an object — this refers to the object to the left of the dot. Finally, the default binding kicks in when none of the other rules apply: in non-strict mode this falls back to the global object (window in browsers), and in strict mode it is undefined.

Arrow functions introduced in ES6 do not follow these rules at all. Instead, they inherit this from their enclosing lexical scope at the time they are defined. This makes arrow functions especially useful for callbacks and event handlers, where a regular function would lose its this binding. For example, when you pass a method as a callback to setTimeout, the implicit binding is lost because setTimeout calls the function without an object context. Using an arrow function or bind() solves this problem.

A common mistake is using arrow functions as object methods. Since arrow functions do not have their own this, defining a method with an arrow function means this will not refer to the object — it will refer to whatever this was in the surrounding scope, which is often the global object or undefined.

Understanding these binding rules is critical for debugging context-related bugs in JavaScript. When this is not what you expect, trace back through the four rules to determine which one applies to your specific call site.

Key Points

  • this is determined at call time, not definition time
  • Rule 1: new binding - this = new instance
  • Rule 2: Explicit binding (call/apply/bind) - this = specified object
  • Rule 3: Implicit binding (obj.method()) - this = object left of dot
  • Rule 4: Default binding - this = window (or undefined in strict mode)
  • Arrow functions inherit this from enclosing scope

Code Examples

Object Method

const person = {
  name: "Alice",
  greet() {
    console.log("Hi, I'm " + this.name);
  }
};

person.greet();
// "Hi, I'm Alice"

// this = object left of the dot

Implicit binding: object left of dot

Standalone Function

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

showThis();
// In browser: Window object
// In strict mode: undefined

// No object = default binding

Default binding: no object = global

call() / apply()

function greet(greeting) {
  console.log(greeting + ", " + this.name);
}

const bob = { name: "Bob" };
const sue = { name: "Sue" };

greet.call(bob, "Hello");
// "Hello, Bob"

greet.apply(sue, ["Hi"]);
// "Hi, Sue"

// First argument becomes 'this'

Explicit binding: first arg = this

bind()

const person = {
  name: "Alice",
  greet() {
    console.log("Hi, " + this.name);
  }
};

const greet = person.greet;
greet();  // undefined (lost binding!)

const boundGreet = person.greet.bind(person);
boundGreet();  // "Hi, Alice"

// bind() permanently sets 'this'

Hard binding: permanently set this

Arrow Functions

const person = {
  name: "Alice",
  regularFunc() {
    console.log(this.name);  // "Alice"

    const arrow = () => {
      console.log(this.name);  // "Alice"
    };
    arrow();
  }
};

// Arrow functions inherit 'this'
// from their enclosing scope

Lexical this: inherits from enclosing scope

new Keyword

function Person(name) {
  this.name = name;
  this.greet = function() {
    console.log("Hi, " + this.name);
  };
}

const alice = new Person("Alice");
alice.greet();  // "Hi, Alice"

// 'new' creates fresh object
// and binds it to 'this'

Constructor binding: this = new instance

Lost Binding

const person = {
  name: "Alice",
  greet() {
    console.log("Hi, " + this.name);
  }
};

// BUG: 'this' is lost in callback
setTimeout(person.greet, 100);
// "Hi, undefined"

// The method is passed as plain
// function, losing its context

Common bug: callback loses context

Fixed with Arrow

const person = {
  name: "Alice",
  greet() {
    console.log("Hi, " + this.name);
  }
};

// FIX 1: Arrow function wrapper
setTimeout(() => person.greet(), 100);
// "Hi, Alice"

// FIX 2: Use bind
setTimeout(person.greet.bind(person), 100);
// "Hi, Alice"

Arrow function preserves this

Common Mistakes

  • Losing this when passing methods as callbacks
  • Using arrow functions as object methods
  • Forgetting that this in nested functions is different

Interview Tips

  • Know all 4 binding rules in order of precedence
  • Explain why arrow functions are useful in callbacks
  • Be able to fix "this" issues with bind or arrow functions

Related Concepts