One of the most frequently asked JavaScript interview questions is:
What is
thisin JavaScript and how does it work?
Many developers memorize rules such as:
this === window;
or
arrow functions don't have this
but struggle when interviewers ask:
What determines the value of
this?
The most important thing to understand is:
thisis determined by how a function is called, not where it is defined.
What is this?#
this is a special keyword that refers to an object associated with the current execution context.
The value of this is decided at runtime.
Example:
const user = {
name: "John",
greet() {
console.log(this.name);
},
};
user.greet();
Output:
John
Here:
this === user;
because the function was called using:
user.greet();
Why Does JavaScript Need this?#
Imagine creating multiple objects:
const user1 = {
name: "John",
};
const user2 = {
name: "Sarah",
};
Without this, every method would need hardcoded references.
const user = {
name: "John",
greet() {
console.log(user.name);
},
};
This breaks when reused.
With this:
const user = {
name: "John",
greet() {
console.log(this.name);
},
};
The method becomes reusable for different objects.
3. Global Context & Function Invocation Rules#
In browsers:
console.log(this);
Output:
window;
Because the global execution context is the browser window.
Browser Example#
var name = "John";
console.log(this.name);
Output:
John
Equivalent to:
window.name;
Rule #2: Function Invocation#
Consider:
function greet() {
console.log(this);
}
greet();
In non-strict mode:
window;
In strict mode:
undefined;
Strict Mode Example#
"use strict";
function greet() {
console.log(this);
}
greet();
Output:
undefined;
This prevents accidental global object access.
4. Method Invocation Rule#
When a function is called as an object's method:
object.method();
this refers to that object.
Example:
const user = {
name: "John",
greet() {
console.log(this.name);
},
};
user.greet();
Output:
John
Interview Trap#
const user = {
name: "John",
greet() {
console.log(this.name);
},
};
const fn = user.greet;
fn();
Output:
undefined
(or window.name in non-strict mode)
Why?
Because:
fn();
is a normal function call.
The connection to user is lost.
5. Constructor Functions Rule#
When using new:
function User(name) {
this.name = name;
}
const user = new User("John");
JavaScript creates a new object and binds this to it.
Equivalent to:
const user = {};
user.name = "John";
Output:
{
name: "John";
}
6. Arrow Functions & Lexical Binding#
Arrow functions do NOT create their own this.
Instead, they inherit this from the surrounding scope.
Example:
const user = {
name: "John",
greet: () => {
console.log(this.name);
},
};
user.greet();
Output:
undefined
Why?
Because the arrow function uses the surrounding this.
It does not receive:
this === user;
Normal Function vs Arrow Function#
Normal function:
const user = {
name: "John",
greet() {
console.log(this.name);
},
};
Output:
John
Arrow function:
const user = {
name: "John",
greet: () => {
console.log(this.name);
},
};
Output:
undefined
Common React Example#
Bad:
class App {
handleClick() {
console.log(this);
}
}
Passing directly:
<button onClick={this.handleClick}>
may lose context.
Historically developers used:
this.handleClick = this.handleClick.bind(this);
inside constructors.
Nested Functions Problem#
const user = {
name: "John",
greet() {
function inner() {
console.log(this.name);
}
inner();
},
};
user.greet();
Output:
undefined
Why?
Because:
inner();
is a normal function call.
Solution 1: Store Reference#
const user = {
name: "John",
greet() {
const self = this;
function inner() {
console.log(self.name);
}
inner();
},
};
Output:
John
Solution 2: Arrow Function#
const user = {
name: "John",
greet() {
const inner = () => {
console.log(this.name);
};
inner();
},
};
Output:
John
Arrow functions inherit the surrounding this.
7. Explicit Binding: call(), apply(), and bind()#
call() immediately invokes a function and sets this.
function greet() {
console.log(this.name);
}
const user = {
name: "John",
};
greet.call(user);
Output:
John
Explicit Binding with apply()#
Works like call() but arguments are passed as an array.
function greet(city) {
console.log(this.name, city);
}
const user = {
name: "John",
};
greet.apply(user, ["Delhi"]);
Output:
John Delhi
Explicit Binding with bind()#
Unlike call and apply:
bind();
does NOT execute immediately.
It returns a new function.
function greet() {
console.log(this.name);
}
const user = {
name: "John",
};
const boundFn = greet.bind(user);
boundFn();
Output:
John
call vs apply vs bind#
| Method | Executes Immediately | Returns Function |
|---|---|---|
| call | Yes | No |
| apply | Yes | No |
| bind | No | Yes |
8. 'this' inside Event Handlers & Classes#
button.addEventListener("click", function () {
console.log(this);
});
Output:
<button>
Inside event listeners:
this === element;
Event Handler with Arrow Function#
button.addEventListener("click", () => {
console.log(this);
});
Output:
window;
(or outer scope)
Arrow functions do not get event-bound this.
Classes and this#
class User {
constructor(name) {
this.name = name;
}
greet() {
console.log(this.name);
}
}
const user = new User("John");
user.greet();
Output:
John
Here:
this === user;
9. Common Interview Q&A#
What Determines the Value of this?#
Not where the function is written.
Instead:
How the function is called
determines this.
Do Arrow Functions Have Their Own this?#
No.
They inherit this from the surrounding lexical scope.
Why Is bind() Useful?#
It permanently fixes the value of this.
const fn = greet.bind(user);
Useful when passing methods as callbacks.
Why Does React Use Arrow Functions Frequently?#
Arrow functions preserve lexical this.
This avoids losing context when functions are passed around.
Senior-Level Interview Answer#
The value of
thisin JavaScript is determined by how a function is invoked. In global scope,thisusually refers to the global object. In object methods, it refers to the object before the dot. Constructor functions bindthisto newly created instances vianew. Functions can explicitly setthisusing call, apply, and bind. Arrow functions are different because they do not have their ownthis; instead they inherit it lexically from the surrounding scope. Understanding invocation patterns rather than memorizing rules is the key to masteringthis.
Key Takeaways#
- Dynamic Binding: The value of
thisis determined dynamically at runtime based on how a function is called, not where it is written. - Global Context: Points to
window(orglobalin Node.js), resolving toundefinedinside strict-mode execution. - Arrow Functions: Do not bind their own
this; they inherit it lexically from their surrounding declaration context. - Explicit Binding: Use
call(),apply(), orbind()to explicitly force a specific context object ontothis. - Event Listeners: Inside event callbacks,
thisnaturally points to the DOM element that received the event.