Strict mode (ES5) is a variant of the language that removes some error-prone features and turns some silent failures into errors. Code that is not strict is informally called sloppy. ECMA-262 lists the differences in Annex C, The Strict Mode of ECMAScript.
What code is strict
| Code | Strict when |
|---|---|
| Global code | The script starts with a Use Strict Directive |
| Function code | Its body has the directive, or it is contained in strict code |
| Module code | Always |
| Class definitions | Always, including the extends expression |
| Eval code | It has the directive, or it is a direct eval from strict code |
new Function bodies | Only if the body has the directive |
Strictness is lexical, and it cannot be switched off inside strict code. A CommonJS module in Node.js is sloppy unless it has the directive. A strict function can call a sloppy one, and each keeps its own rules.
function f() {
'use strict';
return this === undefined;
}
f(); // true: this is not converted to the global object
Restrictions on syntax
These are early errors, reported as a SyntaxError before the code runs.
| Not allowed in strict code | Example |
|---|---|
implements, interface, let, package, private, protected, public, static and yield as identifiers | let private = 1; |
| Legacy octal literals, and decimals with a leading zero | 010, 09 |
| Legacy octal and non-octal escapes in strings | '\1', '\8' |
eval or arguments as a binding name | let eval;, function arguments() {} |
eval or arguments as an assignment or update target | arguments = 1;, eval++; |
eval or arguments as a catch parameter | catch (eval) {} |
| Duplicate parameter names | function f(a, a) {} |
delete of a plain name | delete x; |
The with statement | with (o) {} |
A function declaration as a labelled statement, or as the body of an if | if (a) function f() {} |
Before ES2015, a duplicate key in an object literal was also an error in strict code, and function declarations in blocks were not allowed. Both restrictions are gone. Function declarations in blocks are simply block-scoped.
Changes at run time
| Operation | Sloppy code | Strict code |
|---|---|---|
| Assign to an undeclared name | Creates a global property | ReferenceError |
| Write to a non-writable property, or one with no setter | Ignored | TypeError |
| Add a property to a non-extensible object | Ignored | TypeError |
| Write a property of a primitive | Ignored | TypeError |
delete a non-configurable property | false | TypeError |
this of null or undefined | The global object | Stays as given |
this of a primitive | Wrapped in an object | Stays as given |
arguments | Mapped to named parameters | Independent of them |
arguments binding | Assignable | Immutable |
arguments.callee | The function | TypeError |
eval variables | Added to the calling scope | Stay in the eval’s own scope |
function.caller, function.arguments | May exist as an extension | Not allowed on strict functions |
See the this binding and
the arguments object for the
detail, and Eval and with for
eval.
What it does not change
- Types, operators and built-ins are the same in both modes.
- HTML-like comments depend on the goal symbol, not on strictness, so they are valid in a strict script but not in a module.