An ES module contains no `'use strict'` pragma anywhere. Is its code strict, can you opt out, and does a function defined in that module stay strict when it is later called as a callback from non-strict code?
answer
- the pragma is redundant here
- no wrapper or entry point relaxes it
- strictness follows the code, not the caller
- some violations fail before evaluation
basics
~20 sModule code is strict by definition, so the pragma is redundant and there is no way to opt out. Strictness is lexical, not caller-dependent: a function written inside a module stays strict wherever non-strict code later calls it.
solid answer
~50 sYes, it is strict — the specification defines module code as strict mode code, so `'use strict'` at the top of a module is a no-op you can delete. There is no opt-out: no pragma, wrapper or IIFE relaxes it, and the strictness is fixed by where the code is *written*, not how it is reached. That is why a function exported from a module and handed to non-strict code as a callback is still strict when invoked: a bare call sees `this === undefined` rather than the global object, and an assignment to an undeclared name throws a `ReferenceError` instead of creating a global. Some violations are not even runtime errors — `with`, octal literals like `012`, and duplicate parameter names are syntax errors, so the module fails to parse and never runs at all.
code
javascript · 21 lines// module code — no pragma anywhere, still strict
// runtime consequence: undeclared assignment throws
try {
missing = 1;
} catch (e) {
console.log(e.constructor.name); // "ReferenceError"
}
// an IIFE does not relax it
(function () {
try {
alsoMissing = 2;
} catch (e) {
console.log(e.constructor.name); // "ReferenceError"
}
})();
// strictness is lexical: this stays undefined on a bare call
export function whoAmI() { return this; }
console.log(whoAmI()); // undefinedgo deeper
Know that you never need to write 'use strict' in a module file because module code is already strict, and that undeclared assignments throw there instead of quietly creating globals.
Explain that strictness is fixed when the source is parsed and inherited by everything nested inside, so no wrapper or call site changes it, and separate the syntax-error violations from the runtime ones.
Show you can read the failure mode: a module that never evaluated points to a parse-time strict violation across the whole file, while a mid-run ReferenceError or TypeError points to one line. Explain why the pairing with module scope is what actually seals the global namespace.
Own the argument for unconditional strictness at a codebase level: opt-in safety settings drift, per-file pragmas rot, and a mode fixed by the loading mechanism is one fewer thing review has to police.
## Strict by construction A module body is strict mode code by definition. You do not opt in with a pragma and you cannot opt out with anything. Writing `'use strict'` at the top of a module is legal but does nothing, which is why most modern codebases have deleted those lines from module files. This is a deliberate design decision. Modules were a clean break: a new loading path with no legacy code depending on sloppy-mode behaviour, so the safer semantics could be made unconditional rather than opt-in. ## "Can I opt out?" — no, and here is why the usual tricks fail Candidates often reach for a wrapper: ```js // module code — still strict, all of it (function () { undeclared = 1; // ReferenceError })(); ``` Strictness in ECMAScript is a property of *code*, decided when it is parsed, and it is inherited inwards: every function, class and block nested inside strict code is strict too. Nesting cannot escape outwards. Nor can a different entry point relax it — reaching the module through a dynamic `import()` from sloppy code does not change how the module's own source was parsed. The two genuine escape hatches are not really escapes: an indirect `eval` of a string, and code in a *separate* non-module file. Both are new pieces of code with their own parse, not the module's body loosening up. ## Lexical, not caller-dependent This is the part interviewers push on. Strictness travels with the function, not with the call site: ```js // in a module export function whoAmI() { return this; } ``` Hand `whoAmI` to any non-module, non-strict code and let it call `whoAmI()` with no receiver: the result is `undefined`, not the global object. The reverse also holds — a sloppy-mode function called from inside a module is still sloppy and still gets the global object substituted for a missing receiver. Each function carries the strictness of the source text it was written in. This matters in practice for callbacks. A pre-modules API that documented "your handler is called with `this` set to the global object when you pass a plain function" behaves differently once your handler lives in a module: `this` is now `undefined` and any `this.something` inside it throws a TypeError. ## Parse-time versus runtime consequences It helps to sort the effects into two buckets, because they fail very differently. **Parse time — the module never runs.** These are syntax errors in strict code, so the failure arrives before a single statement executes and no partial side effects occur: ```js with (obj) { } // SyntaxError const n = 012; // SyntaxError (legacy octal) function f(a, a) { } // SyntaxError (duplicate parameter) delete someVariable; // SyntaxError (delete on a plain identifier) ``` **Runtime — the module runs until it hits the line.** Assignment to an undeclared name throws `ReferenceError` instead of creating a global; writing to a non-writable or frozen property throws `TypeError` instead of failing silently; a plain call gets `this === undefined`. Being able to sort a given failure into the right bucket is a good signal in an interview, because it tells you where to look: a parse-time failure means the whole file is suspect, while a runtime one points at a single line. ## Why this is the module leaf's problem Strictness is what makes module scope airtight. Module scope alone stops declarations from becoming globals — but sloppy mode has a back door: `x = 1` with no declaration creates a global property from anywhere. Implicit strict mode closes it. Together the two rules give the real guarantee: **a module cannot add to the global namespace by accident.** That pairing, not either half on its own, is what the question is testing. ## Answering it cleanly A complete answer is three sentences: module code is strict by specification, there is no opt-out at any granularity, and strictness is lexical so it follows the function to wherever it is called. Then give one parse-time example and one runtime example to show you know the failures differ in kind.
- If a module fails because it contains `with (obj) {}`, when does that failure surface?At parse time, before any of the module's statements run. `with` is a syntax error in strict code, and module code is strict, so the module never evaluates and produces no partial side effects. That is different from an undeclared assignment, which is a runtime ReferenceError reached only when execution gets to that line.
- Does loading a module through a dynamic `import()` from non-strict code relax its strictness?No. Strictness is decided when the module's own source text is parsed, and the parse goal is Module regardless of who requested it. The importing code's mode is irrelevant — it is a separate piece of source with its own strictness.
- Is there any value left in writing `'use strict'` at the top of a module file?None semantically — it is a no-op string expression. It usually survives in files converted from scripts. Deleting it is safe and removes a false signal that strictness here is opt-in. The pragma still matters in non-module files, which is why it has not disappeared from codebases.
saying these in an interview costs you the question
- Thinks a module is sloppy unless you write 'use strict'
- Believes an IIFE or block can restore sloppy mode inside a module
- Says strictness depends on who calls the function
- Assumes every strict violation is a runtime error
- Thinks importing from sloppy code relaxes the module