Strict mode removes error-prone legacy behavior, makes invalid writes and implicit globals fail visibly, and changes receiver and arguments semantics. Modules and classes already run in strict mode.
Migrate legacy scripts under tests, replace global and eval-dependent behavior with explicit module contracts, and verify the transformed production bundle rather than assuming a source directive controls every loaded script.
Strict mode is enabled with the `"use strict"` directive and rejects error-prone behavior such as accidental globals and silent assignment failures. JavaScript modules and class bodies already execute with strict semantics.
Modern JavaScript modules and class bodies are strict by default. Regular scripts and regular functions still need the directive if you want strict behavior there.
"use strict";
// Your JavaScript code starts here.
Place "use strict" at the beginning of a script or function. It must appear before other executable statements. Comments are allowed before it, but normal code is not.
"use strict";
price = 499; // ReferenceError: price is not defined
function calculateTotal() {
"use strict";
total = 100; // ReferenceError
}
calculateTotal();
Without strict mode, assigning to a name that was never declared can create a global variable by mistake. Strict mode blocks this immediately.
"use strict";
message = "Hello"; // ReferenceError
let title = "JavaScript";
const year = 2026;
The delete operator is for deleting object properties. It cannot delete declared variables or function declarations in strict mode.
"use strict";
let count = 1;
function showCount() {
return count;
}
// delete count; // SyntaxError
// delete showCount; // SyntaxError
const user = { name: "Asha" };
delete user.name; // This is allowed.
In older non-strict JavaScript, a function could accidentally use the same parameter name twice. Strict mode treats this as a syntax error because it makes code confusing.
"use strict";
// SyntaxError: Duplicate parameter name not allowed
// function add(price, price) {
// return price + price;
// }
function add(price, tax) {
return price + tax;
}
Legacy octal numbers such as 010 are confusing because they look like decimal numbers. Strict mode rejects the old format. Use the modern 0o prefix for octal values.
"use strict";
// let oldOctal = 010; // SyntaxError
let modernOctal = 0o10;
console.log(modernOctal); // 8
Strict mode throws an error when code tries to write to read-only properties, getter-only properties, or non-extensible objects. Without strict mode, these mistakes may fail silently.
"use strict";
const person = { name: "Uttam" };
Object.defineProperty(person, "id", {
value: 101,
writable: false
});
person.id = 202; // TypeError
"use strict";
const circle = {
radius: 10,
get area() {
return Math.PI * this.radius * this.radius;
}
};
circle.area = 500; // TypeError
In a normal function call, strict mode leaves this as undefined. Non-strict mode may replace it with the global object, which can hide bugs.
"use strict";
function showThis() {
console.log(this);
}
showThis(); // undefined
If you write ES modules, strict mode is already enabled automatically. This means a file loaded with <script type="module"> behaves strictly even without writing "use strict".
Because modules and classes are strict by default, most modern projects already benefit from strict rules through bundlers, frameworks, or module-based scripts.
<script type="module" src="app.js"></script>
A directive prologue containing exactly `"use strict"` enables strict mode for a classic script or for one function body. It must appear before ordinary statements in that scope. A directive inside a function with non-simple parameters such as defaults, rest, or destructuring is a syntax error, so place strictness at the script or module boundary.
ECMAScript modules are strict automatically, including imported modules. All parts of class declarations and class expressions are also strict. Adding a directive inside them is redundant. The most maintainable modernization path is usually module conversion rather than scattering directives through individual functions.
Strictness is lexical, not a switch for code called later. A strict caller can invoke a non-strict function and vice versa; each function follows the mode of its own source. Concatenated classic scripts can also interact unexpectedly if build tooling changes directive position, so test the actual emitted bundle.
Strict mode is supported in modern engines, but old or nonconforming hosts are not a reason to use incompatible fallback syntax in current application code. Set explicit runtime targets and transpile syntax where necessary while preserving strict semantics.
A standalone strict function receives `undefined` as `this` instead of the global object, and explicit primitive receivers are not boxed. This exposes detached-method mistakes and prevents accidental writes through `this` from becoming global state.
Assigning to an undeclared identifier throws `ReferenceError` rather than creating a global property. Assignment to a non-writable property, getter-only property, or non-extensible object can throw instead of failing silently. These failures are valuable because they identify a violated invariant at the write site.
Deleting an unqualified identifier is a syntax error, and deleting a non-configurable property can throw. Duplicate parameter names are rejected in strict functions, and legacy octal literal syntax is not allowed. The `with` statement is forbidden because it makes name resolution unpredictable and blocks optimization.
Strict direct `eval` does not introduce bindings into the surrounding scope, and strict code restricts access to legacy caller and arguments introspection. Do not use eval as a migration mechanism; parse a defined data format or expose a narrow command registry instead.
In strict functions with simple parameters, the `arguments` object does not alias named parameters. Changing `arguments[0]` does not change the parameter, and changing the parameter does not update `arguments[0]`. Use rest parameters when a true array of remaining arguments is the intended API.
`arguments.callee` and related stack-inspection properties are restricted. Name recursive functions explicitly, keep stack inspection in Error objects and debugging tools, and avoid code that depends on a caller function being discoverable at runtime.
Strict mode does not make JavaScript statically typed, deeply immutable, or automatically secure. It removes or changes error-prone semantics and enables clearer optimization, but input validation, authorization, escaping, dependency review, and tests remain necessary.
Functions created with the Function constructor do not inherit strictness from the surrounding scope; their source must contain its own directive if required. Avoid runtime code generation for application logic because it complicates policy, source maps, auditing, and content security restrictions.
Add strict mode under tests, then repair failures by category. First find implicit globals, detached receivers, silent writes, duplicate parameters, legacy octal syntax, `with`, and eval-dependent scope behavior. A single directive can expose several assumptions, so avoid mixing the migration with unrelated feature changes.
For browser scripts, move shared state behind modules and explicit exports. Top-level module bindings do not become global object properties, and top-level `this` is undefined. Code that expected `window.someName` must import it or deliberately attach a documented integration surface.
Third-party legacy scripts should be isolated rather than edited blindly. Loading one classic script separately can preserve its own mode while application modules remain strict. Verify license and maintenance status, replace abandoned dependencies, and avoid wrapping unknown source in a way that changes top-level semantics.
Watch for failures that were previously silent. A caught TypeError after an invalid write may reveal code that continued with stale state. Repair the state transition and add a regression assertion; do not add an empty catch merely to restore old visible behavior.
Verify strictness with behavior at a controlled test boundary, such as a standalone function returning `this`, rather than shipping mode-detection tricks throughout the application. Prefer lint and build configuration that parses source as modules and rejects accidental classic-script assumptions.
Test the emitted artifact in every supported environment. Bundlers can wrap modules, transform classes, split chunks, and inject runtime helpers. The source may be strict while a separately loaded plugin or inline script is not, so failures should retain source URL and mapped release information.
Lint rules can catch undeclared names, duplicate parameters, invalid this usage, eval, and legacy constructs before runtime. Type checking adds receiver and property constraints but does not replace tests for generated bundles and host integration.
A successful migration has no new implicit global properties, no receiver-dependent regressions, and no swallowed write failures. Monitor error fingerprints after release and keep tests for the exact legacy assumptions that were removed.
Explore 500+ free tutorials across 20+ languages and frameworks.