The 'this' Keyword
How 'this' works in different contexts: global, object, arrow functions, bind/call/apply
Understanding 'this' in JavaScript
The this keyword is one of the most confusing aspects of JavaScript. Unlike other languages
where this always refers to the current instance, in JavaScript this depends on
how a function is called, not where it's defined.
The 4 Rules of 'this'
- Default Binding — Global object (or undefined in strict mode)
- Implicit Binding — The object calling the method
- Explicit Binding — Manually set via call, apply, or bind
- new Binding — The newly created object
1. Default Binding
When a function is called standalone (not as a method), this refers to the global object (or undefined in strict mode):
function showThis() {
console.log(this);
}
showThis(); // Window (browser) or global (Node)
// In strict mode
"use strict";
function showThisStrict() {
console.log(this);
}
showThisStrict(); // undefined
2. Implicit Binding
When a function is called as a method of an object, this refers to that object:
const user = {
name: "Alice",
greet() {
console.log(`Hello, I'm ${this.name}`);
}
};
user.greet(); // "Hello, I'm Alice" — this = user
// ⚠️ Losing implicit binding
const greetFn = user.greet;
greetFn(); // "Hello, I'm undefined" — this = global/undefined
// Common in callbacks
setTimeout(user.greet, 1000); // "Hello, I'm undefined"
3. Explicit Binding: call, apply, bind
Force this to be a specific value:
function introduce(greeting, punctuation) {
console.log(`${greeting}, I'm ${this.name}${punctuation}`);
}
const person = { name: "Bob" };
// call — arguments passed individually
introduce.call(person, "Hi", "!"); // "Hi, I'm Bob!"
// apply — arguments passed as array
introduce.apply(person, ["Hello", "."]); // "Hello, I'm Bob."
// bind — returns a new function with fixed 'this'
const boundIntro = introduce.bind(person);
boundIntro("Hey", "?"); // "Hey, I'm Bob?"
// Partial application with bind
const sayHiToBob = introduce.bind(person, "Hi");
sayHiToBob("!"); // "Hi, I'm Bob!"
4. new Binding
When using new with a constructor, this refers to the newly created object:
function Person(name) {
// 'this' is the new object being created
this.name = name;
this.sayHi = function() {
console.log(`Hi, I'm ${this.name}`);
};
}
const alice = new Person("Alice");
alice.sayHi(); // "Hi, I'm Alice"
// What 'new' does:
// 1. Creates new empty object
// 2. Links it to Person.prototype
// 3. Binds 'this' to new object
// 4. Returns the object (if no explicit return)
Arrow Functions: Lexical 'this'
Arrow functions don't have their own this. They inherit this from their enclosing scope:
const obj = {
name: "Object",
// Regular function — has its own 'this'
regularMethod() {
console.log(this.name); // "Object"
// Problem: nested function loses 'this'
setTimeout(function() {
console.log(this.name); // undefined
}, 100);
},
// Arrow function — inherits 'this'
arrowMethod() {
console.log(this.name); // "Object"
// Solution: arrow inherits 'this' from arrowMethod
setTimeout(() => {
console.log(this.name); // "Object" ✓
}, 100);
}
};
obj.regularMethod();
obj.arrowMethod();
⚠️ Note: Arrow functions cannot be used as constructors and cannot be bound with call/apply/bind.
'this' in Classes
class Counter {
constructor() {
this.count = 0;
// Method 1: Bind in constructor
this.incrementBound = this.increment.bind(this);
}
increment() {
this.count++;
console.log(this.count);
}
// Method 2: Arrow function property
incrementArrow = () => {
this.count++;
console.log(this.count);
};
}
const counter = new Counter();
// Regular method loses 'this' when extracted
const inc = counter.increment;
inc(); // Error: Cannot read property 'count' of undefined
// Bound method works
const boundInc = counter.incrementBound;
boundInc(); // 1
// Arrow property works
const arrowInc = counter.incrementArrow;
arrowInc(); // 2
Binding Priority
When multiple rules apply, priority order (highest to lowest):
| Priority | Binding Type | Example |
|---|---|---|
| 1 (highest) | new binding | new Fn() |
| 2 | Explicit binding | fn.call(obj) |
| 3 | Implicit binding | obj.fn() |
| 4 (lowest) | Default binding | fn() |
💡 Key Takeaways
- •
thisis determined by how a function is called, not where it's defined - • Use
bind,call, orapplyto explicitly setthis - • Arrow functions inherit
thisfrom their enclosing scope - • In classes, use arrow properties or bind methods to preserve
this - • When in doubt, console.log(
this) to see what it refers to