What does the "use strict" directive do in JavaScript, and where exactly must it appear in a script or function body to take effect?
answer
- opt-in dialect, not an engine flag
- must head the script or function body
- first statement, or it is a no-op
- string literal only, never a computed value
- classes and modules are strict already
basics
~20 s"use strict" switches a whole script or a single function body into strict mode, a stricter dialect where silent failures throw and undeclared assignments are errors. It works only as the very first statement of that script or function body.
solid answer
~50 sStrict mode is an opt-in ECMAScript dialect added in ES5. You enter it with the literal string statement `"use strict"` placed in the *directive prologue* — the run of statements at the start of a script or a function body that are nothing but string literals. Put anything else first and the string is just a harmless expression that does nothing, with no warning. That gives you two granularities: the whole script, or one function at a time. Inside strict code, assigning to an undeclared name throws a `ReferenceError` instead of creating a global, writes that used to fail silently throw a `TypeError`, `this` is `undefined` in a plain call rather than the global object, and things like `with` and legacy octal literals become syntax errors. Module code and class bodies have been strict automatically since ES2015, and strictness is lexical, so nested functions inherit it.
code
javascript · 9 linesfunction sloppy() {
const x = 1;
"use strict";
undeclared = 2;
return undeclared;
}
console.log(sloppy());
console.log(typeof globalThis.undeclared);go deeper
Be able to say that "use strict" must be the first statement of a script or a function body, and name two things it changes — undeclared assignments throw, and silent write failures become errors.
Explain the directive prologue rule precisely: a leading string literal, no escapes, no concatenation, and no diagnostic when it is misplaced. Be ready to say which code is strict without a directive.
Show that you reason about strictness as a lexical, parse-time property: how concatenation moves the boundary, why per-function directives are the safe migration unit, and how you verify the mode of shipped code.
Own the policy question — whether the codebase standardises on modules so strictness stops being something anyone types, and how you keep injected or third-party classic scripts from quietly running under different rules.
## Two dialects in one language ECMAScript 5 (2009) wanted to fix a set of early design mistakes without breaking the millions of pages that depended on them. The compromise was a second dialect: the same syntax, parsed and executed under a stricter rule set, which you opt into. That dialect is strict mode. The key thing to internalise is that strict mode is not a runtime switch. There is no engine flag you flip from inside the language, no variable you set, no `if` you can wrap it in. The strictness of any piece of code is fixed at parse time by where that code lexically sits. ## The directive prologue, precisely A *directive prologue* is the longest initial sequence of statements in a script or function body that consist of nothing but a string literal. `"use strict"` counts as a directive only when it appears there, and only when the literal is exactly `"use strict"` or `'use strict'` with no escape sequences and no line continuation. `"use strict"` is a perfectly ordinary string and enables nothing. What follows from that rule: - Comments before the directive are fine — comments are not statements. - Other directive-shaped strings may precede it; the prologue can hold several. - One real statement before it ends the prologue, and the directive silently degrades into a useless expression statement. - A computed value never works: `'use' + ' strict'` and `const d = 'use strict'; d;` do nothing. - **No error is reported for a misplaced directive.** That is the trap — the code keeps running in sloppy mode and looks strict. ```javascript function f() { const ready = true; // a real statement ends the prologue "use strict"; // now just an expression statement oops = 1; // still silently creates a global } ``` ## Two granularities The directive is legal at the top of a script (a classic `<script>` body or a non-module file) and at the top of a function body — a function declaration, a function expression, a method, or a getter/setter. It is *not* legal at the top of a block, and an arrow function with an expression body has no place to put it. One restriction surprises people: a function whose parameter list is *non-simple* — it uses defaults, rest, or destructuring — may not carry the directive at all, and doing so is a `SyntaxError`: ```javascript function g(a = 1) { "use strict"; // SyntaxError: illegal 'use strict' directive } ``` The reason is ordering: parameter initialisers are evaluated before the body runs, so the parser refuses code whose parameters would be evaluated under a strictness the body then changes. ## Code that is already strict Since ES2015, module code and class bodies — constructors, methods, static blocks, field initialisers — are strict with no directive at all. Strictness is also lexical and inherited: every function nested inside strict code is strict, and a *direct* `eval` call inside strict code evaluates its string as strict code with its own variable scope. ## What the dialect actually changes - Assigning to an undeclared identifier throws `ReferenceError` instead of creating a global. - Writes that used to fail silently — to a frozen or non-writable property, to a getter-only accessor, to a non-extensible object — throw `TypeError`. - `delete` of a non-configurable property throws `TypeError`; `delete someVariable` is a `SyntaxError`. - `this` is `undefined` in a plain call, and `call`/`apply` arguments are passed through without substitution or boxing. - Legacy octal literals (`010`), octal string escapes, `with`, and duplicate parameter names are syntax errors. - `arguments` no longer stays aliased to the named parameters, and `arguments.callee`, `fn.caller` and `fn.arguments` throw. ## The concatenation trap Because the script-level directive covers the *whole script*, gluing files together changes meaning. Put a strict file first in a naive concatenation and every following file becomes strict; paste a strict file into the middle and it silently loses its directive. This is exactly why every tool that combines files wraps each one in its own function or emits real modules. ## Checking at runtime There is no `isStrict()` built-in, but the `this` rule gives you one: ```javascript const strictHere = (function () { return this === undefined; })(); ``` The answer describes the code where that IIFE is *written*, since strictness is lexical. ## Why it still matters With modules and classes strict by default, a lot of new code never types the directive. But classic scripts, inline `<script>` blocks, injected snippets, and older bundles are all sloppy unless they say otherwise — and interviewers ask because the difference explains a whole family of "why did this silently do nothing" bugs.
- Why does putting the directive in a variable, like `const mode = 'use strict'; mode;`, fail to enable strict mode?Because the directive is recognised at parse time by its literal shape, not evaluated at runtime. The parser looks for an initial statement that is exactly the string literal `"use strict"` or `'use strict'`, with no escapes and no concatenation. A variable reference is an ordinary expression statement, so the parser never sees a directive and the code stays sloppy — with no diagnostic.
- How would you scope strict mode to one function without risking the rest of a legacy file?Put the directive at the top of that function body instead of the top of the script. Strictness is lexical, so only that function and anything nested inside it becomes strict; the surrounding file keeps its old semantics. That is the standard incremental-migration move — convert one function, test, then move on — and it also survives being concatenated with other files.
- Is there any way to detect at runtime whether the currently executing code is strict?Yes, by reading `this` from a plain call: `(function () { return this === undefined; })()` is `true` in strict code and `false` in sloppy code, where `this` is substituted with the global object. It reports the strictness of the place the function is *written*, not the caller, because strictness is a lexical property fixed at parse time.
saying these in an interview costs you the question
- Thinks "use strict" works anywhere in the file
- Believes a misplaced directive raises an error
- Says strict mode is a runtime flag you can toggle
- Claims strict mode's main purpose is speed
- Thinks a strict function makes its callees strict