Back to JavaScript
JavaScript
medium
mid

How does the value of this behave in Node.js compared to 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.

3 min read·~6 min to think through

this rules are the same — what differs is the outer context in browser vs Node.

Top-level this

Contextthis
Browser script (non-module)window (= globalThis)
Browser moduleundefined
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:

js
function f() { console.log(this); }
f();                          // strict: undefined; sloppy: globalThis
obj.f = f; obj.f();           // obj
f.call(x);                    // x
new f();                      // new instance

Arrow functions

Arrows capture this lexically from their surrounding scope — they have no own this:

js
const obj = {
  name: "A",
  fn() { return () => this.name; },
};
obj.fn()();   // "A" — the arrow saw `this` of the method

Strict 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

js
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 binding

Fix: arrow methods (greet = () => ...) or .bind(this) in constructor — or just call via the instance.

Practical advice

  • Use globalThis instead of window/global for 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.

Senior engineer discussion

Seniors prefer arrow callbacks + explicit binding patterns, and use `globalThis` for cross-runtime code (browser/Node/Workers/Deno).

Related questions