My Journey Through `this` in JavaScript: From Confusion to Clarity
Swabri Musa

Swabri Musa @skanenje

About: interested in information Powered by knowledge

Joined:
May 8, 2024

My Journey Through `this` in JavaScript: From Confusion to Clarity

Publish Date: May 14
0 0

When I first started learning JavaScript, one word kept showing up in every tutorial, every error message, and every weird behavior I couldn't explain: this.

At first, I thought I understood it — "this means the object, right?" But then I wrote a function that behaved differently than I expected. Then I used it inside a callback... and it broke. The more I used this, the less I understood it.

So I decided to stop guessing — and finally understand how this really works.

This blog is the journey I wish I had when I started. If you’re new to JavaScript or have ever muttered, “Why is this undefined?”, then this one’s for you.

Part 1: What is this, Really?

Let’s start from the top.

In JavaScript, this refers to the execution context of a function — in other words, who is calling the function. Unlike other languages where this is fixed to the class or object, JavaScript’s this is dynamic — it can change depending on how a function is called.

Think of it like this: every time a function runs, JavaScript sets up an environment — an “execution context” — and part of that setup is deciding what this should point to.

That’s the core idea:

this is determined by the call site (where the function is called), not where it was defined.

Part 2: The Building Blocks — Execution Context

Every time JavaScript runs code, it creates an execution context — an environment where the code executes. There are three major types:

  • Global context – the default one. In browsers, this points to the window object.
  • Function context – when you call a function. this depends on how you call the function.
  • Eval context – rarely used, so we’ll skip it.

Let’s test the global context:

console.log(this); // In browsers, logs: Window
Enter fullscreen mode Exit fullscreen mode

So far, so good. But the real fun starts when we look at functions…

Part 3: Four Ways this is Set (The Binding Rules)

Let’s walk through the 4 primary ways JavaScript decides what this means in a function.

1. Default Binding

If you just call a function without any context:

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

sayHello(); // In browsers: logs Window (or undefined in strict mode)
Enter fullscreen mode Exit fullscreen mode
  • In non-strict mode, this is the global object (window in browsers).
  • In strict mode, this is undefined.

Beginner Tip: Strict mode is safer. Use "use strict"; at the top of your file or function to avoid bugs.

2. Implicit Binding

When you call a function as a method of an object, this points to that object.

const user = {
  name: "Alice",
  greet() {
    console.log(`Hi, I’m ${this.name}`);
  }
};

user.greet(); // Hi, I’m Alice
Enter fullscreen mode Exit fullscreen mode

Seems simple, right?

But watch this curveball:

const greet = user.greet;
greet(); // Oops! this is now window or undefined
Enter fullscreen mode Exit fullscreen mode

By pulling the function out, we lost the context. That’s a common beginner trap.

3. Explicit Binding

JavaScript gives you tools to control this manually with call, apply, and bind.

function introduce(role) {
  console.log(`${this.name} is a ${role}`);
}

const person = { name: "Bob" };

introduce.call(person, "Developer"); // Bob is a Developer
introduce.apply(person, ["Designer"]); // Bob is a Designer

const boundFn = introduce.bind(person, "Engineer");
boundFn(); // Bob is an Engineer
Enter fullscreen mode Exit fullscreen mode

🛠️ Use these when you need to control this precisely — like in event handlers or reused functions.

4. new Binding

Calling a function with new creates a brand-new object and binds this to it.

function Car(model) {
  this.model = model;
}

const myCar = new Car("Toyota");
console.log(myCar.model); // Toyota
Enter fullscreen mode Exit fullscreen mode

Here, this refers to the new object being created. That's constructor magic.

⚡ Climax: Enter Arrow Functions — and Lexical this

Arrow functions behave differently — they don’t get their own this. Instead, they "borrow" it from the place where they're defined (lexical scope).

const team = {
  name: "Dev Team",
  arrowFunc: () => {
    console.log(this.name);
  },
  regularFunc: function () {
    console.log(this.name);
  }
};

team.regularFunc(); // Dev Team
team.arrowFunc();   // undefined or window.name
Enter fullscreen mode Exit fullscreen mode

Arrow functions do not bind this — great for callbacks, terrible for object methods.

Gotchas and Fixes: Pitfalls I Tripped Over

Losing this in a callback:

const app = {
  name: "MyApp",
  start: function () {
    setTimeout(function () {
      console.log(this.name); // undefined
    }, 1000);
  }
};
Enter fullscreen mode Exit fullscreen mode

Fix with arrow function:

setTimeout(() => {
  console.log(this.name); // MyApp
}, 1000);
Enter fullscreen mode Exit fullscreen mode

Or save context:

const self = this;
setTimeout(function () {
  console.log(self.name);
}, 1000);
Enter fullscreen mode Exit fullscreen mode

Nested function madness:

const group = {
  name: "Study Group",
  show: function () {
    function inner() {
      console.log(this.name); // undefined
    }
    inner();
  }
};

group.show();
Enter fullscreen mode Exit fullscreen mode

Fix with arrow function:

show: function () {
  const inner = () => {
    console.log(this.name); // Study Group
  };
  inner();
}
Enter fullscreen mode Exit fullscreen mode

The “Aha!” Moment: Practice Makes Perfect

Here’s a final example that combines it all:

const event = {
  title: "Tech Talk",
  organizers: ["Alice", "Bob"],
  announce: function () {
    console.log(`Event: ${this.title}`);
    this.organizers.forEach(function (organizer) {
      console.log(`${organizer} is organizing ${this.title}`);
    });
  }
};

event.announce();
Enter fullscreen mode Exit fullscreen mode

The forEach function loses this, so it doesn’t know about title.

Fix with arrow function:

this.organizers.forEach((organizer) => {
  console.log(`${organizer} is organizing ${this.title}`);
});
Enter fullscreen mode Exit fullscreen mode

Boom. Now this works like we expect — because arrow functions keep this from the announce method.

Wrapping Up: How I Learned to Stop Worrying and Love this

Understanding this isn't about memorizing rules — it's about recognizing patterns:

  • Where was the function called? That’s what defines this.
  • Arrow functions are great for keeping this consistent.
  • Use bind, call, or apply when you need to take control.
  • Practice with real examples — try tweaking code and logging this.

this may seem confusing at first, but once you see how it flows through your code, it becomes a powerful tool — not a mystery.

Your Turn

Try this: Take a function you wrote recently and ask yourself — “What is this right now?” Log it. Play with it. Break it. Then fix it.

Still have questions? Drop them below. Let’s decode JavaScript — together.

Want to Go Deeper?

Comments 0 total

    Add comment