this, call, apply, and bind
this is determined by a function's call site, not where it's defined; call/apply/bind set it explicitly, and arrow functions have no this of their own.
fn.call(thisArg, ...args) / fn.apply(thisArg, argsArray) / fn.bind(thisArg)
Purpose
this is determined by how a function is called (the “call site”), not by where it’s defined.
call, apply, and bind each set this explicitly; arrow functions instead inherit this from
their enclosing lexical scope, having none of their own.
Syntax
const counter = { count: 0 };
function increment(step) {
this.count += step;
}
increment.call(counter, 1); // this = counter, args passed individually
increment.apply(counter, [1]); // this = counter, args passed as an array
const bound = increment.bind(counter); // returns a new function, this permanently counter
bound(5);
Behavior notes
| Call style | Example | this is |
|---|---|---|
| Method call | obj.method() |
obj — whatever precedes the dot |
| Plain call | someFunction() |
undefined in strict mode/modules |
| Constructor call | new SomeClass() |
The newly created instance |
| Explicit binding | fn.call(obj) / .apply(obj) / .bind(obj) |
obj, set explicitly |
| Arrow function | () => {} |
Inherited from the enclosing lexical scope — no this of its own |
callandapplyinvoke the function immediately with the giventhis;bindinstead returns a new function withthispermanently fixed, callable later.- Detaching a method from its object (
const fn = obj.method;) loses the method-callthis— the detached function is just a plain function now, called however its new call site determines. - Arrow functions cannot have their
thischanged bycall/apply/bindat all — thethisArgargument is simply ignored for them.
Common mistakes
- Passing a method as a bare callback (
element.addEventListener('click', obj.method)) and being surprisedthisisn’tobjinside it — the detachment loses the method-call binding.bindit, or use an arrow function wrapper, to preserve it. - Assuming an arrow function method on an object literal gets that object as
this— it doesn’t; an arrow function used as an object property still has nothisof its own and looks outward to whatever scope the object literal itself was written in.
Runtime notes
Core ECMAScript, identical behavior across every current browser and Node version.