`this` — Four Rules and an Arrow Function
IntermediateIn JavaScript `this` is decided by how a function is called, not where it is defined — except in arrow functions, which have no `this` of their own and inherit it from the surrounding scope.
Overview
This is where Java intuition fails hardest. In Java, this always means the instance the method belongs to. In JavaScript, a plain function has no fixed this; it is bound at call time by one of four rules, and the same function can have a different this on every call. That is why extracting a method from an object breaks it, and why pre-2015 code is full of `const self = this`. Arrow functions were introduced partly to fix this: they do not get their own this at all, so they see whatever was in scope where they were written.
The Four Rules, In Priority Order
Work down the list; the first that applies wins.
// 1. new binding — this is the newly created object
function User(name) { this.name = name }
const u = new User('Asha') // this === u
// 2. explicit binding — call, apply, bind
function greet() { return this.name }
greet.call({ name: 'Ravi' }) // 'Ravi'
const bound = greet.bind(user) // permanently bound
// 3. implicit binding — the object left of the dot
const obj = { name: 'Meera', greet }
obj.greet() // 'Meera'
// 4. default — undefined in strict mode / modules,
// globalThis in sloppy mode
const loose = obj.greet
loose() // undefined (strict) — the classic bugThe Lost-Binding Bug
Passing a method as a callback detaches it from its object. This is the single most common this bug, and it appears constantly with event handlers and array callbacks.
class Cart {
constructor() { this.items = [] }
add(item) { this.items.push(item) } // needs this
}
const cart = new Cart()
;['a', 'b'].forEach(cart.add) // TypeError — this is undefined
// Three fixes, cheapest last:
;['a','b'].forEach(item => cart.add(item)) // arrow wrapper
;['a','b'].forEach(cart.add.bind(cart)) // explicit bind
// or define it as a class field, bound at construction:
class Cart2 {
items = []
add = (item) => { this.items.push(item) } // arrow — lexical this
}Arrow Functions Have No `this`
An arrow function looks up this lexically, exactly like any other variable. That makes it right for callbacks and wrong for object methods.
const timer = {
seconds: 0,
// WRONG: arrow at method level — this is the module, not timer
startBad: () => { setInterval(() => this.seconds++, 1000) },
// RIGHT: regular method, arrow callback inherits its this
start() { setInterval(() => this.seconds++, 1000) },
}
// Pre-2015 you saw this everywhere, doing the same job:
function Timer() {
const self = this
setInterval(function () { self.seconds++ }, 1000)
}Key Points to Remember
- 1`this` is bound by how a function is called, not where it is defined
- 2Priority: new > explicit (call/apply/bind) > implicit (object before the dot) > default
- 3Extracting a method from an object loses its binding — the commonest `this` bug in real code
- 4Arrow functions have no `this`; they inherit it lexically, which is why they are right for callbacks
- 5Never use an arrow function as an object method that needs `this` — it will point at the enclosing scope
Interview Questions
Sign in to ask AriaHow is the value of `this` determined in a regular function?
What is the difference between call, apply and bind?
Why does an arrow function behave differently as an object method than a regular function?
Ask Aria about `this` — Four Rules and an Arrow Function
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.