JavaScript 'this' Interview Questions
Short answer
`this` is decided by how a function is called, not where it is written. Four rules apply in order: `new` binding, explicit binding with call, apply or bind, implicit binding from the object before the dot, and finally the default. Arrow functions opt out entirely and inherit `this` from the surrounding scope.
| Rule | Looks like | `this` becomes |
|---|---|---|
| 1. new binding | new Fn() | The newly created object |
| 2. Explicit binding | fn.call(o) / fn.apply(o) / fn.bind(o) | The object you passed |
| 3. Implicit binding | obj.fn() | obj — whatever is before the dot |
| 4. Default binding | fn() | undefined in strict mode, globalThis otherwise |
| Arrow functions | () => {} | No rule — inherited from the enclosing scope |
What determines the value of `this`?
The call site, not the definition site. This is the single sentence to lead with, because every confusing `this` behaviour in JavaScript follows from it. The same function can produce four different values of `this` depending on how it is invoked, which is why you cannot answer a `this` question by looking at where the function was written — you have to find where it was called.
The rules apply in a fixed precedence order, and working through them in that order turns every puzzle into a mechanical check. Was it called with `new`? Then `this` is the new object. Was it called with `call`, `apply` or a bound wrapper? Then `this` is what was supplied. Was there an object before the dot? Then `this` is that object. Otherwise it is the default — `undefined` in strict mode and in modules, or the global object in sloppy mode.
1function who() { return this; }
2
3const obj = { name: "obj", who };
4
5console.log(obj.who().name);
6// → obj implicit: the object before the dot
7
8console.log(who.call({ name: "called" }).name);
9// → called explicit
10
11console.log(new who() instanceof who);
12// → true new: a fresh object
13
14console.log(who());
15// → undefined default, in a module or strict mode
16// (globalThis in a sloppy-mode script)Why does `this` get lost when you pass a method around?
Because implicit binding depends on the call site, and extracting a method destroys the call site. `obj.greet` is just a reference to a function — the connection to `obj` exists only in the moment of the `obj.greet()` call. Assign it to a variable, pass it as a callback, or hand it to `setTimeout`, and the function is later called plainly, so rule four applies and `this` is `undefined`.
1const user = {
2 name: "Arun",
3 greet() { return `hi ${this.name}`; },
4};
5
6// 1. Assigned to a variable
7const fn = user.greet;
8console.log(fn());
9// → TypeError: Cannot read properties of undefined (reading 'name')
10
11// 2. Passed as a callback
12setTimeout(user.greet, 0);
13// → same problem: setTimeout calls it plainly
14
15// 3. Passed to an array method
16["a"].forEach(user.greet);
17// → same again
18
19// Fixes: bind it, or wrap it so the call site is preserved
20setTimeout(user.greet.bind(user), 0);
21setTimeout(() => user.greet(), 0);
22["a"].forEach(user.greet, user); // some methods take thisArgThe wrapper version is worth understanding rather than just copying. `() => user.greet()` works not because arrow functions are magic but because the arrow function's body contains a full `user.greet()` call — the dot is back, so implicit binding applies as normal. That is a much better answer than "arrow functions fix this", which is the thing most candidates say and which is not quite true.
How are arrow functions different?
Arrow functions have no `this` of their own at all. They are not bound to anything at call time — they simply do not participate in the rules, so a reference to `this` inside one resolves outward through the scope chain to the nearest enclosing function that does have one. That is why `call` and `apply` cannot change an arrow function's `this`: there is nothing there to change.
1const timer = {
2 seconds: 0,
3 startBroken() {
4 setInterval(function () { this.seconds++; }, 1000);
5 // → `this` is not `timer`; nothing increments
6 },
7 startWorking() {
8 setInterval(() => { this.seconds++; }, 1000);
9 // → inherits `this` from startWorking, which is `timer`
10 },
11};
12
13const arrow = () => this;
14console.log(arrow.call({ a: 1 }));
15// → undefined (module scope) — call cannot override an arrow
16
17// And as a METHOD, an arrow is the wrong choice:
18const bad = { name: "x", greet: () => `hi ${this?.name}` };
19console.log(bad.greet());
20// → hi undefined there is no enclosing function, so `this`
21// is the module scope, not `bad`So the rule to state is a placement rule, not a preference. Use an arrow function when you want the surrounding `this` — callbacks, effects, handlers defined inside a method or component. Use a regular function when the function needs its own `this` — object methods, constructors, and prototype methods. Saying that as one sentence answers several likely follow-ups at once.
A detail worth volunteering is that class fields holding arrow functions are per-instance rather than shared on the prototype. That is the trade being made: you spend one function object per instance in exchange for a method that can be detached safely. For a handful of components it is irrelevant; for a list of ten thousand rows each holding four handlers, it is a real cost and worth knowing you chose it.
What is the difference between call, apply and bind?
All three set `this` explicitly. `call` and `apply` invoke the function immediately and differ only in how arguments are passed — individually for `call`, as an array for `apply`. `bind` invokes nothing; it returns a new function permanently tied to the `this` you supplied, which is what makes it right for callbacks you are handing to someone else.
1function intro(greeting, punct) {
2 return `${greeting}, ${this.name}${punct}`;
3}
4const me = { name: "Arun" };
5
6console.log(intro.call(me, "Hi", "!"));
7// → Hi, Arun! arguments listed
8
9console.log(intro.apply(me, ["Hello", "."]));
10// → Hello, Arun. arguments in an array
11
12const bound = intro.bind(me, "Hey");
13console.log(bound("?"));
14// → Hey, Arun? partially applied, called later
15
16// bind is permanent — it cannot be re-bound
17console.log(bound.call({ name: "Someone" }, "!"));
18// → Hey, Arun! the original binding still winsThat last line is a favourite follow-up. A bound function ignores any later attempt to change its `this`, including a second `bind`. The one thing that does override it is `new` — constructing a bound function creates a fresh object and uses that, because `new` sits above explicit binding in the precedence order. Being able to explain that ordering is a strong signal that you learned the rules rather than the symptoms.
This is 1 of 80+ questions in the JavaScript Interview Kit
Get every question with detailed answers, follow-ups and real code — plus coding challenges and a last-minute revision sheet. One-time payment, instant access.
⚡ Get the JavaScript Interview Kit → ₹299What is `this` inside an event handler?
With `addEventListener` and a regular function, `this` is the element the listener is attached to — the DOM sets it explicitly, which is really rule two in disguise. With an arrow function it is whatever the surrounding scope had, which is usually the component or module. The `event.currentTarget` property gives you the element in both cases, which is why it is the more reliable choice.
1button.addEventListener("click", function () {
2 console.log(this);
3 // → <button> the element the listener is on
4});
5
6button.addEventListener("click", () => {
7 console.log(this);
8 // → the enclosing scope's `this`, NOT the button
9});
10
11// currentTarget works either way, and survives refactors:
12button.addEventListener("click", (e) => {
13 console.log(e.currentTarget);
14 // → <button>
15});
16
17// target vs currentTarget matters when children exist:
18// target = what was actually clicked (maybe an inner <span>)
19// currentTarget = what the listener is attached toThere is a reason apply survived even though spread can now do the same job. Passing an array of arguments through is still clearer in code that builds argument lists dynamically, and it appears throughout older library source you will read. Modern code usually writes `fn.call(obj, ...args)` instead, which is the same thing with the array expanded at the call site.
How does `this` behave in classes and with React?
Class bodies always run in strict mode, so a detached method gets `undefined` rather than the global object — which is why the React class-component era was full of constructor binding. Every `this.handleClick = this.handleClick.bind(this)` line in an older codebase exists purely because passing `this.handleClick` to `onClick` extracts the method and destroys the implicit binding.
1class Toggle extends React.Component {
2 state = { on: false };
3
4 handleClick() { this.setState({ on: !this.state.on }); }
5
6 render() {
7 return <button onClick={this.handleClick}>toggle</button>;
8 // → TypeError: Cannot read properties of undefined (reading 'setState')
9 }
10}
11
12// Fix 1 — bind in the constructor
13constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); }
14
15// Fix 2 — a class field arrow, which captures `this` lexically
16handleClick = () => { this.setState({ on: !this.state.on }); };
17
18// Function components remove the category entirely — there is no
19// receiver to lose, because there is no object.That last comment is the point worth making if the conversation turns to hooks. Function components do not solve the `this` problem cleverly; they remove it, because state comes from a closure rather than from an object. When someone asks why hooks replaced classes, the disappearance of `this` binding is one of the three answers the React team themselves gave, alongside logic reuse and lifecycle methods grouping code by timing rather than by concern.
What is `this` at the top level and in modules?
It depends on the context, and the answer changed with modules. In a classic script in a browser, top-level `this` is `window`. Inside an ES module it is `undefined`, because modules are always strict and have their own scope. In Node's CommonJS modules it is `module.exports`, which is an empty object. This inconsistency is exactly why `globalThis` was added — it is the one expression that reliably names the global object everywhere.
1// classic <script> in a browser
2console.log(this === window);
3// → true
4
5// inside an ES module (type="module" or .mjs)
6console.log(this);
7// → undefined
8
9// inside a CommonJS module in Node
10console.log(this === module.exports);
11// → true
12
13// everywhere, reliably:
14console.log(typeof globalThis);
15// → objectOne more context worth having ready, because it appears in output questions: a nested regular function inside a method does not inherit the method's `this`. It gets its own, resolved by the same four rules — and since it is usually called plainly, that means undefined. This is precisely the bug the old `const self = this` idiom existed to work around, and the reason arrow callbacks inside methods feel so natural today.
How do you answer a `this` output question?
Work the precedence list out loud, in order, every time. It takes ten seconds, it is right on cases you have never seen, and the interviewer can hear the method rather than guessing whether you recognised the example. Most `this` puzzles are constructed specifically to defeat pattern matching, so a memorised answer usually fails on the second variation.
- Find the call site — where is the function actually invoked, not where it is written?
- Is it an arrow function? If so, ignore the rules and look at the enclosing scope.
- Was it called with `new`? Then `this` is the new object.
- Was it called with call, apply, or is it a bound function? Then `this` is what was supplied.
- Is there an object immediately before the dot? Then `this` is that object.
- Otherwise it is the default: `undefined` in strict mode or a module, `globalThis` in sloppy mode.
One extra habit helps on trick questions: check whether the function was extracted from its object anywhere between definition and call. That single step catches the majority of puzzles, because losing the receiver is the mechanism nearly all of them are built on — whether the extraction is an assignment, a callback, a destructure, or a method passed straight into another function.
Can you change `this` for an arrow function?
No. call, apply and bind all accept an arrow function without error, but the thisArg is ignored because arrow functions have no own binding to replace. If you need to control `this`, the function has to be a regular one.
What is `this` inside a standalone function in strict mode?
undefined. In sloppy mode it would be the global object, which is what allowed a forgotten `new` to quietly write properties onto window. Since ES modules and class bodies are always strict, undefined is the answer you will see in modern code.
Does bind create a new function every time?
Yes, and that matters in React. Calling .bind() inside render produces a new function on every render, so a memoised child sees a changed prop and re-renders. Bind once in the constructor, or use a class field arrow function, so the reference stays stable.
What is `this` in a callback passed to map or forEach?
undefined by default, because the array method calls your function plainly. Both accept an optional second argument, thisArg, which sets it — but an arrow function inheriting the surrounding `this` is the more common modern solution.
Why does `this` work differently in getters and setters?
It does not — the same rules apply. A getter is invoked through property access on an object, so implicit binding gives you that object. It only looks different because there is no visible call, which makes the receiver easy to overlook.
Frequently asked questions
- What is `this` in JavaScript?
- A reference decided at call time rather than at definition time. The same function can see four different values depending on how it is invoked, which is why you have to look at the call site to answer any question about it — the definition tells you almost nothing on its own.
- What are the rules for `this` binding?
- Four, in precedence order: new binding when called with new, explicit binding with call, apply or bind, implicit binding from the object before the dot, and default binding otherwise — undefined in strict mode, globalThis in sloppy mode. Arrow functions sit outside the rules entirely.
- Why does `this` become undefined when I pass a method as a callback?
- Because implicit binding comes from the call site, and extracting the method removes it. obj.greet is only a function reference; the link to obj exists solely during an obj.greet() call. Bind it, or wrap it in an arrow function that performs the full obj.greet() call.
- How do arrow functions handle `this`?
- They have none of their own and do not participate in the binding rules, so `this` resolves lexically to the nearest enclosing function that has one. That makes them ideal for callbacks and wrong for object methods, and it means call, apply and bind cannot change their `this`.
- What is the difference between call, apply and bind?
- call and apply both invoke the function immediately with a chosen `this`, differing only in whether arguments are passed individually or as an array. bind does not invoke anything — it returns a new function permanently bound to that `this`, optionally with some arguments pre-filled.
- Can a bound function be rebound?
- No. A second bind, or a call with a different thisArg, is ignored — the original binding wins. The one exception is new, which creates a fresh object and uses that, because new binding sits above explicit binding in the precedence order.
- What is `this` inside an event handler?
- With addEventListener and a regular function, it is the element the listener is attached to, because the DOM sets it explicitly. With an arrow function it is the surrounding scope's value. event.currentTarget gives you the element in both cases and is the safer choice.
- Why did React class components need to bind methods?
- Because passing this.handleClick to onClick extracts the method from the instance, and class bodies are strict mode, so `this` becomes undefined rather than the global object. Binding in the constructor or using a class field arrow function restores the receiver.
- What is `this` at the top level of a module?
- undefined. ES modules are always in strict mode and have their own scope, unlike a classic script where top-level `this` is window. In Node's CommonJS modules it is module.exports. Use globalThis when you genuinely need the global object.
- Does strict mode change `this`?
- Yes, for the default binding. In sloppy mode a plain function call sets `this` to the global object; in strict mode it is undefined. That converts a silent bug — a forgotten new writing onto window — into an immediate TypeError.
- What is the difference between `this` and self or that?
- self and that are ordinary variables from the pre-arrow era: developers wrote const self = this at the top of a method so a nested callback could reach the outer `this` through the closure. Arrow functions made the pattern unnecessary, but it still appears in older code.
- How do I explain `this` in an interview?
- Give the one-liner — it depends on how the function is called — then list the four rules in precedence order and apply them out loud to the example in front of you. Demonstrating the method matters more than the answer, because it shows you can handle a case you have not seen.
This is 1 of 80+ questions in the JavaScript Interview Kit
Get every question with detailed answers, follow-ups and real code — plus coding challenges and a last-minute revision sheet. One-time payment, instant access.
⚡ Get the JavaScript Interview Kit → ₹299