What does `this` refer to inside a regular JavaScript function that is invoked on its own, as a bare `doThing()`, and how does strict mode change the answer?
answer
- no receiver at the call site
- the fallback rule fires
- two possible values, not one
- strictness of the called function decides
- class bodies and modules are strict
basics
~20 sA bare call supplies no receiver, so default binding applies: this is globalThis in sloppy mode and undefined in strict mode. Class bodies and ES modules are always strict, so undefined is the modern norm.
solid answer
~40 sA bare `doThing()` matches none of the receiver-supplying call forms, so JavaScript falls back to default binding. In sloppy mode `this` becomes the global object, `globalThis` — which is why a stray `this.count = 0` in such a function quietly creates a global property instead of failing. In strict mode `this` is `undefined` instead, so the same line throws `TypeError: Cannot set properties of undefined`. That matters more than it sounds, because strict mode is now the common case: class bodies are always strict and ES module code is always strict, so functions declared there see `undefined`. The practical takeaway is that strict mode converts a silent, hard-to-trace misbinding into a loud error at the exact call that caused it.
code
javascript · 8 linesfunction sloppy() { return this; }
function strict() { 'use strict'; return this; }
console.log(sloppy() === globalThis); // true in a classic script
console.log(strict()); // undefined
// Strictness of the CALLED function decides, not the caller:
(function () { 'use strict'; console.log(sloppy() === globalThis); })(); // truego deeper
Memorise the two outcomes — globalThis in sloppy mode, undefined in strict mode — and be able to point at the call site and say it supplies no receiver.
Explain that the called function's own strictness decides, and that class bodies and ES modules are strict without any directive, so undefined is the usual modern result.
Articulate why the strict-mode TypeError is the better failure: the sloppy default writes real state onto the global object and the symptom appears far from the cause.
Be ready to argue for enforcing strictness uniformly across a codebase and for lint rules that ban this in non-method functions, so this class of defect cannot ship at all.
## What a "bare call" is A bare call is an invocation where the call site hands the function no receiver at all: `doThing()`, `helper()`, `fn()`. There is no `new`, no `.call`/`.apply`/bound function, and no dot immediately before the parentheses. Since the three receiver-supplying rules do not match, the engine applies the last rule — **default binding**. ## The two possible answers Default binding has exactly two outcomes, and which one you get depends on whether the *called function's own code* is strict: ```js function sloppy() { return this; } function strict() { 'use strict'; return this; } sloppy(); // globalThis (in a classic script) strict(); // undefined ``` Note carefully: it is the strictness of the **function being called**, not of the code doing the calling. A sloppy-mode function called from inside strict code still gets `globalThis`. ## Why sloppy mode is the dangerous one With `this === globalThis`, assignments do not fail — they succeed against the wrong object: ```js function init() { this.retries = 3; } init(); globalThis.retries; // 3 — a global appeared out of nowhere ``` Nothing throws. The state you intended to put on an instance is now process-wide, shared by every caller, and the symptom shows up somewhere else entirely — a value that mysteriously persists between operations, or a collision with a property the host already defines on the global object. This is the classic "lost `this`" bug in its most invisible form. ## Why strict mode is the good outcome With `this === undefined`, the very first property access throws: ```js 'use strict'; function init() { this.retries = 3; } init(); // TypeError: Cannot set properties of undefined (setting 'retries') ``` The error names the exact line and fires at the call that caused it, so the stack trace points at the real defect instead of at a distant consumer of the polluted global. This is one of strict mode's most practically valuable changes. ## Where strict mode already applies without you writing it You are far more likely to be in strict mode than not: - **Class bodies** — everything inside a `class`, including methods and static blocks, is strict. - **ES modules** — all module code is strict, whether it's a `.mjs` file, a `<script type="module">`, or a file in a package declaring modules. - Any file or function with an explicit `'use strict'` directive. Only classic non-module scripts, and CommonJS files without the directive, are sloppy by default. ## How to reason about it under pressure When a snippet asks "what does this print", do it in two steps. First, is the call bare? If it names no receiver, you are in default binding. Second, is the called function's code strict? Strict gives `undefined`, sloppy gives `globalThis`. That is the entire decision. A related trap is the plain function nested inside a method: ```js const api = { url: '/users', load() { function fetchIt() { return this.url; } // bare call below return fetchIt(); } }; api.load(); // sloppy: undefined (globalThis.url) — strict: TypeError ``` `load()` had a receiver, but `fetchIt()` does not, and receivers are not inherited from the enclosing call. The inner call site is judged entirely on its own. ## What not to say The two answers interviewers reject are "this is always the global object" (untrue in strict mode, and untrue for every non-bare call form) and "this is undefined whenever you don't set it" (untrue in sloppy mode, where it is quietly the global). Naming both branches, and naming which contexts are strict by default, is what a complete answer looks like.
- If strict code calls a sloppy-mode function with no receiver, which default applies?The sloppy one. The rule looks at the strictness of the function being executed, not of the caller, so that function still sees `globalThis`. Mixed codebases can therefore contain both behaviours side by side, which is a good reason to make strictness uniform.
- Why is the sloppy-mode default considered worse than a thrown error?Because the write succeeds. Properties intended for an instance land on the global object, so state leaks between unrelated operations and may collide with existing globals. The failure surfaces far from its cause, whereas the strict-mode TypeError points straight at the offending call.
saying these in an interview costs you the question
- Says this is always the global object
- Says this is always undefined in a plain call
- Thinks the caller's strictness decides the default
- Believes a nested function inherits the outer method's this
- Assumes ordinary functions are strict by default