Function context
The function context is the object that the keyword this refers to inside a function while it runs. The main rule: the context is determined at the moment the function is called, not at the moment it is declared.
Theory
TL;DR
thisis a reference to the object in whose context the function is currently running.- The value of
thisdepends on how the function is called, not on where it was declared. - A plain call: the global object (
windowin a browser) orundefinedin strict mode. - A method call
obj.method(): the context becomesobj. - A call through
new: the context becomes the newly created object. call,apply,bind: the context is set manually.- Arrow functions have no
thisof their own and take it from the surrounding scope.
Quick example
function showThis() {
console.log(this);
}
showThis(); // in a plain call the context is the global objectIn a browser in sloppy mode:
this === window;In Node.js inside a regular function in strict mode:
this === undefined;The context depends on the way the function is called
| How we call the function | What this will be |
|---|---|
Plain call func() | The global object (window) or undefined in strict mode |
Method call obj.method() | The object obj |
Through new | The newly created object |
Through call / apply / bind | The object you specify manually |
| Inside an arrow function | this is taken from the outer context (lexically) |
A plain call, that is, the global context:
function test() {
console.log(this);
}
test(); // window (or undefined in strict mode)A call as a method of an object:
const user = {
name: "Alice",
sayHi() {
console.log(this.name);
},
};
user.sayHi(); // "Alice"Here this refers to the object user, because the function was called exactly as user.sayHi().
Losing the context
const user = {
name: "Alice",
sayHi() {
console.log(this.name);
},
};
const hi = user.sayHi;
hi(); // undefined, this is lostWhy:
- We passed a reference to the function, but not the object itself.
- The call
hi()is a plain call, without theusercontext.
The fix with bind:
const hi = user.sayHi.bind(user);
hi(); // "Alice"The same trap appears when a method is passed as a callback: setTimeout(user.sayHi, 100) or button.addEventListener("click", user.sayHi).
The context when calling with new
function User(name) {
this.name = name;
}
const u = new User("Alice");
console.log(u.name); // "Alice"Here this points to the newly created object (u). The new operator creates an empty object, makes it the context of the call and returns it, unless the function explicitly returns another object.
call, apply and bind
function greet() {
console.log(this.name);
}
const user = { name: "Maria" };
greet.call(user); // "Maria"
greet.apply(user); // "Maria"
const boundGreet = greet.bind(user);
boundGreet(); // "Maria"| Method | What it does |
|---|---|
call(thisArg, arg1, arg2, ...) | calls the function with the given this and comma-separated arguments |
apply(thisArg, [args]) | the same, but the arguments are passed as an array |
bind(thisArg) | returns a new function with a fixed this, without calling it right away |
Arrow functions and a summary
const obj = {
name: "Alice",
arrow: () => console.log(this.name),
regular() {
console.log(this.name);
},
};
obj.arrow(); // undefined, this is the outer context, not obj
obj.regular(); // "Alice"What matters:
- Arrow functions have no
thisof their own. - They "take"
thisfrom the surrounding lexical scope, that is, from where they were created. - Because of that,
call,applyandbindcannot changethisinside an arrow function.
Summary table:
| Situation | What this will be |
|---|---|
| Plain call | window or undefined |
| Method of an object | The object itself |
new | The new instance |
call, apply, bind | The object you specify manually |
| Arrow function | Inherits this from outside |
The function context is the "owner of the call": whoever calls the function becomes
this.
Common mistakes
- Believing that
thisis decided by where the function is declared. It is not, it is decided by where and how it is called. - Passing a method as a callback without binding it.
setTimeout(user.sayHi, 100)loses the context. You needuser.sayHi.bind(user)or an arrow wrapper() => user.sayHi(). - Writing an object method as an arrow function. Then
thispoints at the surrounding scope rather than the object, andthis.namegivesundefined. - Mixing up
callandapply.calltakes comma-separated arguments,applytakes an array. - Expecting
bindto be overridable. A bound function cannot be rebound with anotherbindor withcall: the first binding wins. - Forgetting about strict mode. Code in modules and classes is always strict, so a plain call there gives
undefined, notwindow.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.