Detailed explanation
In JavaScript, `this` is a value available inside functions whose meaning usually depends on how the function is invoked, not where it was defined. For normal functions, inspect the call site first. In `obj.regular()`, the property call makes `obj` the receiver, so `this.name` reads `'A'`. However, `const fn = obj.regular; fn();` loses that receiver. JavaScript does not permanently attach a method to its object merely because the function is stored as an object property.
For a standalone normal-function call, `this` is `undefined` if the function executes in strict mode. In non-strict mode, it defaults to `globalThis`. With `fn.call(value, arg)` or `fn.apply(value, [arg])`, the caller supplies `this` explicitly; the difference is how arguments are passed. `fn.bind(value)` creates a new function with a fixed receiver for ordinary calls. Non-strict functions replace explicit `null` or `undefined` receivers with the global object and box primitive receivers; strict functions preserve the supplied value.
Calling a constructible function with `new` creates an object, links it to the constructor's prototype, and runs the constructor with that object as `this`. Normally, that object becomes the result, although an explicitly returned object can replace it. When a bound constructor is invoked with `new`, its bound receiver is ignored in favour of the new instance. These rules matter when debugging methods passed as callbacks: the receiving API determines how a normal callback is invoked, so its original object context may disappear.
Arrow functions have no own `this`; they resolve it through their enclosing lexical environment. Consequently, `call`, `apply`, and `bind` cannot change an arrow's receiver, and arrows cannot be constructors. In the example, the object literal does not establish a `this` scope, so `obj.arrow()` uses the surrounding `this`, not `obj`. Its result is not universally `undefined`: `this?.name` depends on the surrounding environment and any existing `name` property. Interviewers look for this distinction and expect you to explain both method extraction and environment-dependent arrow behaviour.
Key points to remember
- Normal-function `this` is determined by invocation, not by where the function is stored.
- `obj.method()` supplies `obj` as the receiver; extracting the method loses that receiver.
- Standalone calls use `undefined` in strict functions and `globalThis` in non-strict functions.
- `call` and `apply` invoke with an explicit receiver; `bind` returns a bound function; `new` supplies a new instance.
- Arrows capture lexical `this`; object literals do not create a new `this` scope.
Common mistakes candidates make
- Assuming a function stored on an object always uses that object as `this`, even when passed as a callback.
- Using an arrow for an object method that needs the receiver, or trying to change its `this` with `bind`.
- Claiming the example's arrow always returns `undefined` without checking its enclosing environment.
Likely follow-up questions
How can you preserve `this` when passing a method as a callback?
Use `obj.method.bind(obj)` or a wrapper such as `() => obj.method()`. The bound function fixes the receiver, while the wrapper performs a property call when invoked.
What is top-level `this`?
In an ES module, top-level `this` is `undefined`; in a browser's classic script, it is the global `this` value, normally `window`. In a Node.js CommonJS module, it is `module.exports`, so top-level arrows behave differently across these environments.
Why does an arrow inside a class method often work well as a callback?
It captures the `this` of that method invocation, so it retains the instance when the enclosing method was called on the instance. It does not acquire a different receiver when another API invokes the callback.
Interview tip: Explain the call-site rules first, contrast arrows with normal functions, and demonstrate receiver loss with an extracted method.
