The "this" Keyword
MedThe `this` keyword refers to the object that is executing the current function. Its value is determined by HOW a function is called, not where it's defined. There are 4 main rules that determine what `this` refers to.
Interactive Visualization
1const person = {2 name: "Alice",3 greet() {4 console.log(this.name);5 }6};78person.greet(); // "Alice"
Understanding The "this" Keyword
The this keyword in JavaScript is one of the most frequently misunderstood features of the language. Unlike most programming languages where this always refers to the current instance of a class, JavaScript determines the value of this dynamically based on how a function is called, not where it is defined. This distinction is the root cause of countless bugs and a favorite topic in JavaScript interviews.
There are four binding rules that determine what this refers to, applied in order of precedence. The highest priority is the new binding: when a function is called with the new keyword, this refers to the newly created object. Next is explicit binding, where you manually set this using call(), apply(), or bind(). The call and apply methods invoke the function immediately with a specified this value, while bind returns a new function with this permanently set. Third is implicit binding, which applies when a function is called as a method of an object — this refers to the object to the left of the dot. Finally, the default binding kicks in when none of the other rules apply: in non-strict mode this falls back to the global object (window in browsers), and in strict mode it is undefined.
Arrow functions introduced in ES6 do not follow these rules at all. Instead, they inherit this from their enclosing lexical scope at the time they are defined. This makes arrow functions especially useful for callbacks and event handlers, where a regular function would lose its this binding. For example, when you pass a method as a callback to setTimeout, the implicit binding is lost because setTimeout calls the function without an object context. Using an arrow function or bind() solves this problem.
A common mistake is using arrow functions as object methods. Since arrow functions do not have their own this, defining a method with an arrow function means this will not refer to the object — it will refer to whatever this was in the surrounding scope, which is often the global object or undefined.
Understanding these binding rules is critical for debugging context-related bugs in JavaScript. When this is not what you expect, trace back through the four rules to determine which one applies to your specific call site.
Key Points
- this is determined at call time, not definition time
- Rule 1: new binding - this = new instance
- Rule 2: Explicit binding (call/apply/bind) - this = specified object
- Rule 3: Implicit binding (obj.method()) - this = object left of dot
- Rule 4: Default binding - this = window (or undefined in strict mode)
- Arrow functions inherit this from enclosing scope
Code Examples
Object Method
const person = { name: "Alice", greet() { console.log("Hi, I'm " + this.name); } }; person.greet(); // "Hi, I'm Alice" // this = object left of the dot
Implicit binding: object left of dot
Standalone Function
function showThis() { console.log(this); } showThis(); // In browser: Window object // In strict mode: undefined // No object = default binding
Default binding: no object = global
call() / apply()
function greet(greeting) { console.log(greeting + ", " + this.name); } const bob = { name: "Bob" }; const sue = { name: "Sue" }; greet.call(bob, "Hello"); // "Hello, Bob" greet.apply(sue, ["Hi"]); // "Hi, Sue" // First argument becomes 'this'
Explicit binding: first arg = this
bind()
const person = { name: "Alice", greet() { console.log("Hi, " + this.name); } }; const greet = person.greet; greet(); // undefined (lost binding!) const boundGreet = person.greet.bind(person); boundGreet(); // "Hi, Alice" // bind() permanently sets 'this'
Hard binding: permanently set this
Arrow Functions
const person = { name: "Alice", regularFunc() { console.log(this.name); // "Alice" const arrow = () => { console.log(this.name); // "Alice" }; arrow(); } }; // Arrow functions inherit 'this' // from their enclosing scope
Lexical this: inherits from enclosing scope
new Keyword
function Person(name) { this.name = name; this.greet = function() { console.log("Hi, " + this.name); }; } const alice = new Person("Alice"); alice.greet(); // "Hi, Alice" // 'new' creates fresh object // and binds it to 'this'
Constructor binding: this = new instance
Lost Binding
const person = { name: "Alice", greet() { console.log("Hi, " + this.name); } }; // BUG: 'this' is lost in callback setTimeout(person.greet, 100); // "Hi, undefined" // The method is passed as plain // function, losing its context
Common bug: callback loses context
Fixed with Arrow
const person = { name: "Alice", greet() { console.log("Hi, " + this.name); } }; // FIX 1: Arrow function wrapper setTimeout(() => person.greet(), 100); // "Hi, Alice" // FIX 2: Use bind setTimeout(person.greet.bind(person), 100); // "Hi, Alice"
Arrow function preserves this
Common Mistakes
- Losing this when passing methods as callbacks
- Using arrow functions as object methods
- Forgetting that this in nested functions is different
Interview Tips
- Know all 4 binding rules in order of precedence
- Explain why arrow functions are useful in callbacks
- Be able to fix "this" issues with bind or arrow functions