How does "this" behave in Node.js? Is it the same as in a browser console
Browser console (script): `this` at top level is `window` (or `globalThis`). Node CommonJS module: top-level `this` is `module.exports` (which is `{}` initially), NOT `global`. Node ESM: top-level `this` is `undefined`. Inside functions: same rules everywhere — depends on call site, strict mode, arrow vs regular.
this rules are the same — what differs is the outer context in browser vs Node.
Top-level this
| Context | this |
|---|---|
| Browser script (non-module) | window (= globalThis) |
| Browser module | undefined |
Node CommonJS (.js / .cjs) | module.exports ({} initially), NOT global |
Node ESM (.mjs / "type": "module") | undefined |
| REPL (Node) | global |
That's why a beginner trying this === global in a Node script gets false — they're in CJS module scope.
Inside functions
The call site determines this:
function f() { console.log(this); }
f(); // strict: undefined; sloppy: globalThis
obj.f = f; obj.f(); // obj
f.call(x); // x
new f(); // new instanceArrow functions
Arrows capture this lexically from their surrounding scope — they have no own this:
const obj = {
name: "A",
fn() { return () => this.name; },
};
obj.fn()(); // "A" — the arrow saw `this` of the methodStrict mode
ES modules and class bodies are strict mode. this inside a plain function call is undefined instead of globalThis — safer, catches bugs.
Class methods
class C {
greet() { return "hi"; }
}
const c = new C();
const m = c.greet;
m(); // TypeError if greet uses this; m's call site lost the bindingFix: arrow methods (greet = () => ...) or .bind(this) in constructor — or just call via the instance.
Practical advice
- Use
globalThisinstead ofwindow/globalfor portable code. - Prefer arrow functions for callbacks to avoid binding loss.
- Be explicit (
.bind,.call,.apply) when passing methods as callbacks.
Interview framing
"Same this rules everywhere — only the outer context differs. In a browser non-module script, top-level this is window. In a Node CommonJS module, it's module.exports, not global. In any ES module, it's undefined. Inside functions, call site wins (object, call/apply/bind, new); arrows capture lexically. Strict mode (everywhere in modules and classes) makes loose calls return undefined instead of the global, which catches bugs. Use globalThis for portable code."
Follow-up questions
- •Why is top-level this {} in Node CJS?
- •How does new change this binding?
- •Why are arrow functions safer for callbacks?
Common mistakes
- •Expecting top-level this in Node to equal global.
- •Method binding lost when passed as callback.
- •Using arrow as a constructor or method that needs this.
Performance considerations
- •Arrow methods per-instance use slightly more memory than prototype methods; negligible in practice.
Edge cases
- •.bind(null) sets this to undefined in strict mode but globalThis in sloppy.
- •Class fields with arrows vs prototype methods — performance trade.
- •this in event handlers (DOM gives currentTarget).
Real-world examples
- •Express middleware (this lost when passing handlers), React class methods needing bind, Node CLI tools.