Hello! Welcome to the next lesson in our journey through JavaScript's core concepts.
In our last lesson, we explored how closures leverage lexical scope, meaning a function's access to variables is determined by where it is defined in the code. We saw this in action with patterns like function factories and private data encapsulation.
Today, we tackle a complementary and often confusing concept: the this keyword. Unlike closures, the value of this is not determined lexically. Instead, it's determined dynamically by how a function is invoked. This lesson will demystify this by explaining the clear, hierarchical rules JavaScript uses to determine its value in any given situation.
Your goal for this lesson is to explain the four rules for determining the this binding in different function invocation contexts. By the end, you'll have a robust mental model for predicting the value of this every time.
The Core Principle: Call-Site and Dynamic Binding
The single most important thing to understand about this in a regular function is that its value is determined at call time. It has nothing to do with where the function is defined, but everything to do with how it is called. This is often called dynamic binding.
To determine the value of this, you only need to look at one place: the call-site, which is the location in your code where the function is actually invoked.
The Four Rules of this Binding
There are four rules that determine the value of this. They are applied in a specific order of precedence. When you need to figure out what this is, you ask these questions in order, and the first one that matches wins.
Let's begin by watching a concise explanation of these rules and their hierarchy.
HTML5DevConf: Kyle Simpson " New Rules For JS"
In this segment from his talk 'New Rules For JS', Kyle Simpson, author of the renowned 'You Don't Know JS' book series, presents the four binding rules for the this keyword in their precise order of precedence. This will form the foundation for our entire lesson.
Watch from 00:31:35 to 00:33:45. Focus on identifying the four rules and, crucially, the order in which he presents them. This hierarchy is the key to resolving any confusion about this.
As you saw, the rules in order of precedence are:
newBinding- Explicit Binding
- Implicit Binding
- Default Binding
Now, let's explore each of these rules in detail.
Rule 1: new Binding (Highest Priority)
When you call a function with the new keyword (i.e., you use it as a constructor), JavaScript performs a few steps under the hood. For our purposes, the most important is this: it creates a brand new, empty object, and sets the this keyword inside that function call to be that new object.
this, call, apply & bind - 33 JavaScript Concepts
The article 'this, call, apply & bind' from 33jsconcepts.com provides an excellent breakdown of what happens during new binding. The conceptual steps it outlines are perfect for understanding the mechanics.
Read the section titled 'Rule 1: new Binding (Highest Priority)'. Pay close attention to the four steps listed under 'What new Does Under the Hood'. This sequence explains precisely how the this context is established for a constructor call.
In short: new Person() makes this inside Person refer to the newly created person object.
Rule 2: Explicit Binding (.call(), .apply(), .bind())
If new is not used, the next question is whether the this context has been explicitly set. JavaScript functions have built-in methodsβcall, apply, and bindβthat allow you to force this to be a specific object, regardless of how the function is called.
This rule has a higher precedence than implicit binding. Even if you call a method on an object, you can override its natural this using .call().
const alice = {
name: "Alice",
greet() {
return `Hi, I'm ${this.name}`;
}
};
const bob = { name: "Bob" };
// Implicit binding would make 'this' = alice
console.log(alice.greet()); // "Hi, I'm Alice"
// Explicit binding overrides implicit binding
console.log(alice.greet.call(bob)); // "Hi, I'm Bob"
We will dive deeper into the differences and use cases for call, apply, and bind in the next lesson. For now, just know that their primary job is to explicitly set the this context.
Rule 3: Implicit Binding (Method Invocation)
If rules 1 and 2 don't apply, JavaScript checks if the function was called as a method on a containing object. This is perhaps the most common case you encounter. When you call a function using dot notation, like user.sayHi(), the object to the "left of the dot" (user) becomes the this context for that call.
this keyword in JavaScript π₯ | Ep.06 - Namaste JavaScript Season 2 π
This video from Akshay Saini provides a clear, practical demonstration of implicit binding using a student object.
Watch from 00:16:46 to 00:19:57. Notice how calling student.printName() makes this inside the printName function refer to the student object itself.
The "Lost Context" Problem
A critical pitfall with implicit binding occurs when you pass an object method as a callback. When the method is assigned to a variable or passed to another function, it loses its connection to the original object. The call-site is no longer obj.method(), so implicit binding does not apply, and we fall through to the final rule.
This is a very common bug pattern, especially with event handlers or setTimeout.
How to Use the "this" Keyword in JavaScript: A Handbook for Devs
The freeCodeCamp article on this has a fantastic explanation and example of the 'Lost Context Problem'.
Read the subsections 'Nested Objects' and 'The Lost Context Problem'. The timer example is a classic demonstration of this issue and shows how bind can be used to solve it by creating a function with a fixed this context.
Rule 4: Default Binding (The Fallback)
If none of the first three rules apply, we have a plain, undecorated function call. In this case, this falls back to the default binding. The behavior here depends on whether you are in strict mode.
- Non-Strict Mode:
thisbecomes the global object (windowin browsers,globalin Node.js). This can lead to accidentally creating or modifying global variables and is generally considered unsafe. - Strict Mode:
thisisundefined. This is much safer, as attempting to access properties onundefinedwill immediately throw an error, alerting you to the problem.
Given that modern JavaScript (ES6 modules, classes) is in strict mode by default, you should almost always assume this will be undefined in a default binding scenario.
this keyword in JavaScript π₯ | Ep.06 - Namaste JavaScript Season 2 π
Akshay Saini's video gives a detailed look at default binding, explaining the difference between strict and non-strict modes and introducing the concept of 'this substitution'. This level of detail aligns with your goal of understanding the underlying mechanics.
Watch from 00:06:37 to 00:12:30. Focus on how using 'use strict' changes the value of this from the window object to undefined. The explanation of 'this substitution' clarifies why non-strict mode defaults to the global object.
The Exception: Arrow Functions and Lexical this
So far, all our rules apply to regular functions. Arrow functions (=>) are different. They do not have their own this binding. Instead, they inherit this from their enclosing lexical scope, just like closures inherit access to variables.
This means the value of this inside an arrow function is determined by where the arrow function is defined, not how it is called.
this keyword in JavaScript π₯ | Ep.06 - Namaste JavaScript Season 2 π
This final video segment explains how arrow functions behave differently. It neatly ties the concept of this back to the idea of lexical scope, which we covered in the last lesson.
Watch from 00:27:47 to 00:36:20. The key takeaway is the term 'enclosing lexical context'. An arrow function doesn't care about the four binding rules; it just asks, 'What is this in the scope where I was created?' The nested example at 00:33:45 is particularly insightful.
This lexical behavior makes arrow functions incredibly useful for callbacks, as they automatically "preserve" the this context of their surrounding method, solving the "lost context" problem without needing .bind().
Test Your Knowledge
You now have a complete decision-making framework for determining this. To put it to the test, work through the following interactive examples. For each one, try to predict the output before revealing the answer.
this, call, apply & bind - 33 JavaScript Concepts
The '33 JavaScript Concepts' article provides an excellent quiz to solidify your understanding. Applying the rules to these scenarios is the best way to internalize them.
Go to the 'Test Your Knowledge' section and answer all six questions. For each one, consciously walk through the hierarchy of rules: Is it called with new? Is call/apply/bind used? Is it an implicit method call? Or is it the default? Is it an arrow function?
Conclusion
Understanding this is a milestone in mastering JavaScript. It moves from being a source of confusion to a powerful tool once you internalize the rules that govern its dynamic nature.
Key Takeaways:
- Dynamic vs. Lexical:
thisin regular functions is determined dynamically by the call-site, whereas arrow functions and closures use lexical scope (determined at definition time). - A Hierarchy of Rules: The value of
thisis determined by a clear order of precedence:newBinding:thisis the newly created object.- Explicit Binding:
thisis the object passed tocall,apply, orbind. - Implicit Binding:
thisis the object to the "left of the dot". - Default Binding:
thisisundefined(in strict mode) or the global object.
- Arrow Functions are the Exception: They don't have their own
this. They inherit it from their parent scope, making them ideal for callbacks where context needs to be preserved.
What's Next?
In this lesson, we learned why and when you might need to control the this context. In our next lesson, "Describe how bind, call, and apply can be used to explicitly set the 'this' context of a function," we will take a much deeper dive into the mechanics of explicit binding. We'll explore the subtle differences between these three methods and their practical applications, such as function borrowing and partial application.