JavaScript this guide
Understanding this in JavaScript
A call-site-first explanation of how JavaScript decides what this refers to — default, implicit, explicit, and new binding — with runnable examples.
this is not decided by where a function is written. It is decided fresh at every call, based entirely on the syntax used to make that call. The same function can produce a different this every time it runs.
This guide walks through the binding rules in the order you should check them, then shows the one case — arrow functions — where this behaves completely differently.
The short answer
- Ask one question at every call site: what appears immediately before the function name? That answers what binds this.
- call and apply invoke a function immediately with an explicit this. bind returns a new function with that this permanently attached instead of calling anything.
- new binding overrides everything else: constructing with new always creates a fresh object and binds this to it.
1. Default binding: no object before the function name
A bare call like greet() supplies no receiver. In sloppy mode, this falls back to the global object; in strict mode, it stays undefined. This is the rule that surprises people most, because it applies even when a function was originally read off an object.
A bare call has nothing before it, so default binding applies
function greet() {
console.log(this);
}
greet(); // the global object in sloppy mode, undefined in strict mode2. Implicit binding: an object sits right before the call
obj.method() supplies obj as this — this is implicit binding, and it is the rule most everyday code relies on.
The moment that method is copied into a bare variable and called without an object in front of it, implicit binding no longer applies, and default binding takes over instead.
The same greet function loses its receiver once detached
const person = {
name: "Ada",
greet() {
console.log(this.name);
},
};
person.greet(); // "Ada" — implicit binding
const greet = person.greet;
greet(); // undefined — default binding, the receiver is gone3. Explicit binding: call, apply, and bind
call and apply let you specify this directly and invoke the function immediately; they differ only in how they pass the remaining arguments (individually vs. as an array).
bind does not call anything. It returns a brand-new function with this permanently locked to the value you gave it — calling that returned function with a different receiver later has no effect.
call invokes immediately; bind only returns a new function
function show() {
console.log(this.id);
}
const target = { id: 42 };
show.call(target); // 42
const bound = show.bind(target);
bound(); // 42 — locked in, regardless of how bound is later called4. new binding takes priority over all of these
Calling a function with new triggers the Construct operation: a fresh object is created, linked to the function’s prototype, and bound as this for that call — regardless of how the function would normally resolve this otherwise.
new always binds this to the newly created instance
function Person(name) {
this.name = name;
}
const ada = new Person("Ada");
console.log(ada.name); // "Ada"5. Arrow functions opt out of all of these rules
An arrow function has no binding rule of its own. It permanently captures whatever this already existed in its surrounding scope at creation time — call, apply, bind, and even new cannot override it.
That makes an arrow function behave like a closure over this rather than a function with its own binding rule — see the Closures guide, and the this & Closures tracer, for exactly how that plays out.