JavaScript Strict Mode Table
| Change | Sloppy mode | Strict mode |
|---|---|---|
undeclared = 5 | Creates a global variable | Throws ReferenceError - typos become loud |
delete variable | Silently fails (returns false) | Throws SyntaxError |
duplicate parameter names | Last one wins | Throws SyntaxError |
with (obj) { ... } | Allowed | Throws SyntaxError - scope games banned |
this in standalone fn | Global object (window) | undefined - no accidental global writes |
octal literals (0777) | Allowed (as legacy) | Throws SyntaxError - use 0o777 |
arguments.callee | Works | Throws TypeError - recursion by name instead |
Strict mode converts JavaScript's silent failures into loud errors. Turn it on with 'use strict' at the top, and seven categories of mistake that sloppy mode silently accepts become immediate throws. ES modules and class bodies are always strict - new code is strict by default.
Bottom line: every strict mode change is the same design principle - the engine tells you AT the mistake, not three bugs later. Accidental globals throw ReferenceError; silent delete failures throw TypeError; standalone this stops pointing at window (killing accidental global writes through this). The TDZ from let/const is the same philosophy: loud at the source.
The honest part: strict mode is opt-in in scripts but mandatory in ES modules and class bodies. You are almost certainly already writing strict code - the question is whether you know which of your patterns it bans, and why each ban makes debugging faster. The table's seven changes cover the differences that affect real code.
How to use
- Add 'use strict' at the top of a script or function body; modules and classes are already strict.
- Fix what the engine flags: undeclared assignments, duplicate params, octal literals - each was a real bug class.
- Know the with-statement ban: it makes scope unpredictable, which is why it is the only statement strict mode bans outright.
Frequently asked questions
Why does strict mode ban assigning to undeclared variables?
Because that assignment is almost always a TYPO: x = 5 when you meant bar.x = 5 or const x = 5. In sloppy mode the engine silently creates a global variable - polluting the shared namespace and potentially clobbering someone else's value. In strict mode the engine throws a ReferenceError at the exact line, turning a silent namespace pollution into an immediate fix. The fix is always: declare the variable with let, const, or var first.
What does 'use strict' actually change about this?
In sloppy mode, a standalone function call gives this as the global object (window in browsers) - so this.x = value inside a bare function silently writes to window. In strict mode, this in the same call is undefined - writing this.x throws a TypeError. This is the strict-mode version of the TDZ principle: the engine refuses to let you write to something that does not exist, instead of silently creating it.
Why are duplicate parameter names banned in strict mode?
Because with two same-named parameters, the second silently overwrites the first - arguments[0] and arguments[1] disagree with the named parameters, and the function body reads the overwritten value. In sloppy mode this is a confusing but non-crashing bug; in strict mode it is a SyntaxError caught before the function runs. The fix: rename the parameter, or use rest parameters (...args) if the function genuinely takes a variable list.
Are ES modules always strict?
Yes - all ES module code (import/export) runs in strict mode automatically, as do class bodies. You cannot opt out. This means the seven changes in the table are always active in your module code: no accidental globals, no duplicate parameters, no with statement, no octal literals. Script code (non-module) must opt in with the 'use strict' directive, but modules get it for free - which is one reason the module system makes code safer by default.