Decoding 'this': The Most Misunderstood Word in JavaScript
1/23/2026

You can write solid functions and ship features, yet still get tripped up by one tiny word: 'this'.
It may seem harmless and read like plain English, but it leads to a surprising number of bugs, console logs, and those frustrating "why is 'this' undefined?" moments in JavaScript. 😅
The issue isn't lack of experience. It's expectation. We assume 'this' behaves like a stable reference that we can glance at and move on from. However, 'this' is a dynamic value. JavaScript waits until runtime to determine the value. That timing difference is where confusion begins.
Once you stop asking where 'this' exists and start tracing how a function is invoked, the rules become clearer. Everything that follows builds upon that single idea.
What 'this' Really Means in JavaScript 🎯
In JavaScript, the value of 'this' is determined by the execution context, not by scope, file structure, or where the function is defined.
Instead of asking "What does this refer to?", a more helpful question is:
How was this function called?
Answer it, and 'this' stops being a mystery.
🌍 Global Context and Strict Mode 🔒
When 'this' appears outside of any object or class, context matters immediately:
- In browsers, 'this' refers to the global 'window' object.
- In strict mode, 'this' is 'undefined'.
"use strict";
function demo() {
console.log(this);
}
demo(); // undefinedThis behavior exists to prevent silent bugs: strict mode forces you to be explicit instead of accidentally leaking logic into the global scope.
'this' Inside Objects 🧱
When 'this' is used inside an object method, it feels more intuitive:
const user = {
fName: "Sherlock",
lName: 'Holmes',
greet() {
console.log(this.fName);
}
};
user.greet(); // "Sherlock"So far, so good.
Now comes the part that breaks mental models.
What's the expected output here?
const greet = user.greet;
greet();At this point, 'greet' does not copy the object relationship above. It copies only the function value. So 'greet' is no longer being called as a method.
When 'greet()' is invoked, it's a plain function call. JavaScript briefly looks around and asks:
"What are you talking about, Willis?"
Wait, wrong question. It asks:
Who is calling this function?
Answer? No one (which, yes, sounds like prom).
So JavaScript assigns:
this === undefined (in strict mode)
this === window (in sloppy mode)If you actually want to preserve the context, you need to call it as a method:
// explicitly call greet as a method of user
const greet = () => user.greet();Regular Functions vs. Arrow Functions 🏹
With regular functions, 'this' is determined by how the function is called, not where it's defined.
function greet() {
console.log(this.name);
}
const person = {
name: "Nikola",
greet: greet
};
person.greet();The expected output? Here, 'greet()' is invoked as 'person.greet()', so JavaScript assigns 'this' to the item before the dot ('person' in this case).
function greet() {
console.log(this.name);
}
const person = {
name: "Nikola",
greet: greet
};
person.greet(); // "Nikola"Unlike regular functions, where 'this' is dynamic, in arrow functions, 'this' is fixed (or lexical).
function Person() {
this.age = 0;
setInterval(() => {
this.age++;
}, 1000);
}
const p = new Person();Here, the arrow function does not have its own 'this' context. Instead, the enclosing execution context's value is used to define 'this'. The above code snippet runs as expected, incrementing age by 1 every second.
Now, let's look at a common trap.
const person = {
name: "Einstein",
sayName: () => {
console.log(this.name);
}
};
person.sayName();Einstein, right?
WRONG!!
Arrow functions, the divas of the party, ignore the object they're inside of faster than their date the night before. They don't care about 'person'. They care about where they were created, not where they live.
'this' in Event Handlers 🧩
In DOM event handlers, 'this' usually refers to the element that triggered the event.
button.addEventListener("click", function () {
console.log(this); // button
});Switch that function to an arrow function, and the context changes. This subtle difference explains many UI bugs that seem random until you notice the type of function used.
'this' in Classes 🏗️
Inside a class, 'this' refers to the instance being created. Issues can arise when methods are passed around.
class Counter {
count = 0;
increment() {
setTimeout(function () {
this.count++;
}, 1000);
}
}Here, 'this' no longer points to the instance. To preserve the reference, you can use arrow functions or '.bind(this)'.
The Mental Model That Actually Works 💡
Instead of memorizing edge cases, rely on a simple checklist:
✅ Identify how the function is called
✅ Check whether it's a regular function or an arrow function
✅ Confirm whether strict mode is enabled
This approach lets you reason about 'this' before running the code.
If this checklist makes sense but doesn't stick right away, that's normal. Understanding a rule once isn't the same as recognizing it in different situations. Take a look at The 3x Rule: A Simple Trick to Really Learn That JS Concept to see how repetition turns patterns like this into instinct.
At Kadmía, we see this pattern constantly: concepts like 'this', execution context, and event handling don't stick through reading alone. Mastery comes through repetition across small, realistic scenarios. That's why we guide you through focused challenges that emphasize these behaviors, helping you recognize them naturally.
When you can predict 'this' before opening the console, you're no longer reacting to surprises; you're reasoning through them. And that's when it stops being confusing and starts feeling obvious. ✨