👆

The "this" Keyword

intermediate

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
Step 1/2person.greet() is called - look at what's LEFT of the dot
Binding Priority: new → explicit (call/apply/bind) → implicit (dot) → default (global). Arrow functions inherit this lexically from enclosing scope.

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