Toggle theme D

The word "this" sounds simple. In most languages, it refers to the current object — straightforward. But in JavaScript, this changes depending on how a function is called, not just where it's defined. That's where the confusion starts.

What this Actually Represents

Think of this as answering the question: "Who called this function?" The answer determines what this refers to at runtime. It points to the object that invoked the function, not the function itself.

function greet() {
  console.log('Hello, ' + this.name);
}

const alice = { name: 'Alice' };
const bob = { name: 'Bob' };

greet.call(alice);  // 'Hello, Alice'
greet.call(bob);    // 'Hello, Bob'

Same function, different this — because the caller changes.

this in Global Context

When you use this outside of any function or object, it refers to the global object. In browsers, that's window. In Node.js in non-strict mode, it's the global object.

console.log(this);  // In browser: Window object

In strict mode, this outside any function is undefined:

'use strict';
console.log(this);  // undefined

This matters when writing modern JavaScript — strict mode behavior is intentional. It prevents accidental reliance on the global object.

this Inside Objects

Here's the scenario where this makes the most intuitive sense:

const person = {
  name: 'Alice',
  greet: function() {
    return 'Hello, I am ' + this.name;
  }
};

console.log(person.greet());  // 'Hello, I am Alice'

When you call person.greet(), the object person is the caller. So this refers to person. This feels right.

But watch what happens when you extract the method:

const greet = person.greet;
console.log(greet());  // 'Hello, I am ' + undefined

Now there's no object context. The function is called without a caller, so this becomes the global object (or undefined in strict mode). The method "forgets" who it belongs to.

this Inside Functions

Regular functions — not methods, just functions called on their own — have their own this behavior:

function showName() {
  console.log(this.name);
}

const user = { name: 'Charlie' };
user.showName = showName;

showName();              // undefined (no caller context)
user.showName();         // 'Charlie'

A function's this is determined by how it's called, not where it's defined. Call it directly and this is the global object. Attach it to an object and call it through that object, and this is that object.

How Calling Context Changes this

Four rules govern what this refers to:

1. Method callthis is the object before the dot:

obj.method();  // this = obj

2. Direct callthis is the global object (or undefined in strict mode):

func();  // this = global (or undefined)

3. With call/apply/bindthis is explicitly set:

func.call(context);  // this = context
func.apply(context); // this = context
func.bind(context)(); // this = context

4. Arrow functionsthis is lexically inherited from the surrounding scope:

const obj = {
  name: 'Diana',
  greet: () => {
    console.log(this.name);  // this = whatever this is outside obj
  }
};

Arrow functions don't have their own this. They capture it from their enclosing context, which is why they're useful for callbacks where you'd otherwise lose the outer this.

A Practical Example

const counter = {
  count: 0,
  increment: function() {
    this.count++;
  },
  getCount: function() {
    return this.count;
  }
};

counter.increment();
counter.increment();
console.log(counter.getCount());  // 2

When increment runs as counter.increment(), this is counter. Easy.

But what if you pass the method as a callback?

setTimeout(counter.increment, 1000);  // this is NOT counter

The method is extracted and passed as a callback. When it fires, there's no object context — this becomes the global object. That's why this.count++ creates or modifies a global count, not the one on counter.

Arrow functions fix this cleanly:

const counter = {
  count: 0,
  increment: () => {
    this.count++;
  }
};

setTimeout(counter.increment, 1000);  // this is still counter

Wrapping Up

this in JavaScript is all about the caller. It refers to whatever object invoked the function, resolved at call time. That's why extracting methods breaks — the object context disappears.

The rules are simple: method calls get this from the object, direct calls get global/undefined, explicit binding overrides, and arrow functions inherit from their scope. Once you internalize that this is about the call site, not the function, the confusion fades.