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 thewindow
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
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)
- In non-strict mode,
this
is the global object (window
in browsers). - In strict mode,
this
isundefined
.
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
Seems simple, right?
But watch this curveball:
const greet = user.greet;
greet(); // Oops! this is now window or undefined
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
🛠️ 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
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
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);
}
};
Fix with arrow function:
setTimeout(() => {
console.log(this.name); // MyApp
}, 1000);
Or save context:
const self = this;
setTimeout(function () {
console.log(self.name);
}, 1000);
Nested function madness:
const group = {
name: "Study Group",
show: function () {
function inner() {
console.log(this.name); // undefined
}
inner();
}
};
group.show();
Fix with arrow function:
show: function () {
const inner = () => {
console.log(this.name); // Study Group
};
inner();
}
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();
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}`);
});
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
, orapply
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.