docs/beyond/concepts/strict-mode.mdx
Why doesn't JavaScript yell at you when you misspell a variable name? Why can you accidentally create global variables without any warning? And why do some errors just... silently disappear?
// In regular JavaScript (sloppy mode)
function calculateTotal(price) {
// Oops! Typo in variable name - no error, just creates a global
totall = price * 1.1
return total // ReferenceError - but only here!
}
The answer is that JavaScript was designed to be forgiving. Too forgiving. Strict mode is an opt-in way to catch these mistakes early, turning silent failures into actual errors you can fix.
"use strict"
function calculateTotal(price) {
totall = price * 1.1 // ReferenceError: totall is not defined
return total // Never reaches here - error caught immediately!
}
Strict mode is an opt-in restricted variant of JavaScript, introduced in ECMAScript 5 (2009). It catches common mistakes by converting silent errors into thrown exceptions and disabling confusing features. Enable it by adding "use strict" at the beginning of a script or function. According to MDN, strict mode applies different semantics to normal JavaScript: it eliminates some silent errors, fixes mistakes that prevent engine optimizations, and prohibits syntax likely to conflict with future ECMAScript versions.
Think of strict mode like the safety net under a trapeze artist.
Without the net, a small mistake might go unnoticed. The artist might develop bad habits, make minor errors in form, and never realize it until something goes seriously wrong.
With the net in place, those small mistakes become obvious. When you slip, you notice immediately. You can correct your form before bad habits become permanent.
┌─────────────────────────────────────────────────────────────────────────┐
│ SLOPPY MODE vs STRICT MODE │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ SLOPPY MODE (Default) STRICT MODE ("use strict") │
│ ───────────────────── ───────────────────────── │
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ mistakeVar = 5 │ │ mistakeVar = 5 │ │
│ │ ↓ │ │ ↓ │ │
│ │ Creates global │ │ ReferenceError! │ │
│ │ (silent failure) │ │ (caught early) │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ NaN = 42 │ │ NaN = 42 │ │
│ │ ↓ │ │ ↓ │ │
│ │ Does nothing │ │ TypeError! │ │
│ │ (no feedback) │ │ (can't assign) │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │
│ "Forgiving" but dangerous Strict but helpful │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Strict mode doesn't make JavaScript a different language. It just adds guardrails that catch problems before they become bugs.
Add "use strict"; as the very first statement in your file:
"use strict"
// Everything in this file is now in strict mode
let validVariable = 10
invalidVariable = 20 // ReferenceError!
let x = 1
"use strict" // Too late! This is just a string now
invalidVariable = 20 // No error - strict mode isn't active
You can enable strict mode for just one function:
function loose() {
badVariable = "oops" // Creates global (sloppy mode)
}
function strict() {
"use strict"
badVariable = "oops" // ReferenceError! (strict mode)
}
This is useful when adding strict mode to legacy codebases gradually.
Here's the good news: you probably don't need to write "use strict" anymore. The State of JS 2023 survey shows that over 80% of respondents use ES modules in their projects, meaning strict mode is automatically enabled for the vast majority of modern JavaScript code.
ES Modules are automatically in strict mode:
// myModule.js (or any file loaded as type="module")
// No "use strict" needed - it's automatic!
export function greet(name) {
mesage = `Hello, ${name}` // ReferenceError! (strict mode is on)
return message
}
Classes are also automatically strict:
class Calculator {
add(a, b) {
// This method runs in strict mode automatically
reslt = a + b // ReferenceError!
return result
}
}
This is the biggest win of strict mode. JavaScript has many operations that silently fail in sloppy mode. Strict mode turns these into actual errors you can see and fix.
The most common JavaScript mistake. In sloppy mode, assigning to an undeclared variable creates a global:
// ❌ SLOPPY MODE - silent bug
function processUser(user) {
userName = user.name // Typo! Creates window.userName
return userName.toUpperCase()
}
processUser({ name: "Alice" })
console.log(window.userName) // "Alice" - leaked to global!
// ✓ STRICT MODE - catches the bug
"use strict"
function processUser(user) {
userName = user.name // ReferenceError: userName is not defined
return userName.toUpperCase()
}
This single change catches countless typos and copy-paste errors. According to a Stack Overflow analysis, accidental global variable creation is one of the top 10 most common JavaScript bugs, making this strict mode check especially valuable. See Scope & Closures for more on how variable declarations work.
Some properties can't be changed. In sloppy mode, trying to change them does nothing. In strict mode, you get an error:
// ❌ SLOPPY MODE - silent failure
NaN = 42 // Does nothing
undefined = true // Does nothing
Infinity = 0 // Does nothing
const obj = {}
Object.defineProperty(obj, "fixed", { value: 10, writable: false })
obj.fixed = 20 // Does nothing - still 10
// ✓ STRICT MODE - actual errors
"use strict"
NaN = 42 // TypeError: Cannot assign to read-only property
undefined = true // TypeError: Cannot assign to read-only property
const obj = {}
Object.defineProperty(obj, "fixed", { value: 10, writable: false })
obj.fixed = 20 // TypeError: Cannot assign to read-only property 'fixed'
If a property only has a getter (no setter), assignment silently fails in sloppy mode:
const user = {
get name() {
return "Alice"
}
}
// ❌ SLOPPY MODE
user.name = "Bob" // Silent failure
console.log(user.name) // Still "Alice"
// ✓ STRICT MODE
"use strict"
user.name = "Bob" // TypeError: Cannot set property 'name' which has only a getter
Built-in properties like Object.prototype can't be deleted:
// ❌ SLOPPY MODE - silent failure
delete Object.prototype // Returns false, does nothing
delete Math.PI // Returns false, does nothing
// ✓ STRICT MODE - actual errors
"use strict"
delete Object.prototype // TypeError: Cannot delete property 'prototype'
This catches copy-paste errors in function definitions:
// ❌ SLOPPY MODE - silently uses last value
function sum(a, a, b) {
return a + a + b // First 'a' is lost!
}
sum(1, 2, 3) // Returns 7 (2 + 2 + 3), not 6
// ✓ STRICT MODE - syntax error
"use strict"
function sum(a, a, b) { // SyntaxError: Duplicate parameter name
return a + a + b
}
Leading zeros in numbers can cause unexpected behavior:
// ❌ SLOPPY MODE - confusing octal interpretation
const filePermissions = 0755 // This is 493 in decimal!
console.log(filePermissions) // 493
// ✓ STRICT MODE - syntax error for legacy octal
"use strict"
const filePermissions = 0755 // SyntaxError: Octal literals are not allowed
// Use the explicit 0o prefix instead:
const correctPermissions = 0o755 // Clear: this is octal
console.log(correctPermissions) // 493
this Changes in Strict ModeOne of the most important strict mode changes affects the this keyword.
In sloppy mode, when you call a function without a context, this defaults to the global object (window in browsers, global in Node.js):
// ❌ SLOPPY MODE - this = global object
function showThis() {
console.log(this)
}
showThis() // Window {...} or global object
This is dangerous because you might accidentally read or modify global properties:
// ❌ SLOPPY MODE - accidental global modification
function setName(name) {
this.name = name // Sets window.name!
}
setName("Alice")
console.log(window.name) // "Alice" - leaked!
this is undefinedIn strict mode, this remains undefined when a function is called without a context:
// ✓ STRICT MODE - this = undefined
"use strict"
function showThis() {
console.log(this)
}
showThis() // undefined
function setName(name) {
this.name = name // TypeError: Cannot set property 'name' of undefined
}
This makes bugs obvious instead of silently corrupting global state.
<Note> **Arrow functions are different.** They inherit `this` from their surrounding scope regardless of strict mode. This behavior is consistent and not affected by the sloppy/strict distinction. </Note>eval and argumentsStrict mode makes eval and arguments less magical (and less dangerous).
// ❌ SLOPPY MODE - allowed but confusing
var eval = 10
var arguments = [1, 2, 3]
// ✓ STRICT MODE - syntax error
"use strict"
let eval = 10 // SyntaxError: Unexpected eval or arguments in strict mode
let arguments = [] // SyntaxError
eval Doesn't Leak VariablesIn sloppy mode, eval can create variables in the surrounding scope:
// ❌ SLOPPY MODE - eval leaks variables
eval("var leaked = 'surprise!'")
console.log(leaked) // "surprise!" - it escaped!
// ✓ STRICT MODE - eval is contained
"use strict"
eval("var contained = 'trapped'")
console.log(contained) // ReferenceError: contained is not defined
arguments Doesn't Sync with ParametersIn sloppy mode, arguments and named parameters are linked:
// ❌ SLOPPY MODE - weird synchronization
function weirdSync(a) {
arguments[0] = 99
return a // Returns 99! Changed via arguments
}
weirdSync(1) // 99
// ✓ STRICT MODE - no synchronization
"use strict"
function noSync(a) {
arguments[0] = 99
return a // Returns 1 - 'a' is independent
}
noSync(1) // 1
Strict mode reserves words that might be used in future versions of JavaScript:
"use strict"
// These are reserved and cause SyntaxError if used as identifiers:
let implements // SyntaxError
let interface // SyntaxError
let package // SyntaxError
let private // SyntaxError
let protected // SyntaxError
let public // SyntaxError
let static // SyntaxError (except in class context)
This prevents your code from breaking when JavaScript adds new features using these keywords.
with Statement is ForbiddenThe with statement is completely banned in strict mode:
// ❌ SLOPPY MODE - with is allowed but confusing
const obj = { x: 10, y: 20 }
with (obj) {
console.log(x + y) // 30 - but where do x and y come from?
}
// ✓ STRICT MODE - with is forbidden
"use strict"
with (obj) { // SyntaxError: Strict mode code may not include a with statement
console.log(x + y)
}
The with statement makes code unpredictable and impossible to optimize. Use destructuring instead:
// ✓ BETTER - clear and explicit
const { x, y } = obj
console.log(x + y) // 30 - obviously from obj
"use strict" When It's Already OnA frequent mistake is adding "use strict" to code that's already in strict mode:
// myModule.js - ES Module (already strict!)
"use strict" // Unnecessary - modules are always strict
export function greet() {
// ...
}
class MyClass {
myMethod() {
"use strict" // Unnecessary - class bodies are always strict
}
}
This doesn't cause errors, but it's redundant. In modern JavaScript:
| Context | Strict Mode | Need "use strict"? |
|---|---|---|
ES Modules (import/export) | Automatic | No |
| Class bodies | Automatic | No |
Code inside eval() in strict context | Automatic | No |
Regular <script> tags | Sloppy by default | Yes |
| Node.js CommonJS files | Sloppy by default | Yes |
Strict mode catches silent failures — Operations that would silently fail (like assigning to read-only properties) now throw errors you can see and fix.
"use strict" must be first — Place it at the very top of a file or function, before any other statements.
Modules and classes are automatically strict — If you use import/export or classes, strict mode is already on. No need to add the directive.
Accidental globals become errors — The most common bug it catches. Assigning to an undeclared variable throws ReferenceError instead of creating a global.
this is undefined in loose function calls — Calling a function without a context gives this = undefined instead of the global object. This prevents accidental global pollution.
eval is contained — Variables created inside eval() stay inside. They don't leak into the surrounding scope.
Duplicate parameters are forbidden — function f(a, a) {} is a syntax error, catching copy-paste bugs.
The with statement is banned — Use destructuring instead for cleaner, more predictable code.
Reserved words are protected — Words like private, public, interface can't be used as variable names, preparing your code for future JavaScript features.
Use strict mode everywhere — There's no downside. Modern tooling and ES modules make this automatic.
</Info>You get a `ReferenceError`. In sloppy mode, this would silently create a global variable, which is almost never what you want.
```javascript
"use strict"
function example() {
myVar = 10 // ReferenceError: myVar is not defined
}
```
This catches typos like `userName` vs `username` immediately instead of creating mysterious global variables.
It's `undefined`. In sloppy mode, it would be the global object (`window` or `global`).
```javascript
"use strict"
function showThis() {
console.log(this) // undefined
}
showThis()
```
This prevents accidental reads or writes to global properties through `this`.
No. ES Modules are automatically in strict mode. Adding `"use strict"` is harmless but unnecessary.
```javascript
// myModule.js
export function greet() {
// Already in strict mode - no directive needed
mistypedVar = "oops" // ReferenceError (strict mode active)
}
```
The same applies to class bodies, which are also automatically strict.
To catch copy-paste errors. In sloppy mode, duplicate parameters silently shadow each other:
```javascript
// Sloppy mode - confusing behavior
function add(a, a) {
return a + a // The first 'a' is lost, uses second value twice
}
add(1, 2) // Returns 4, not 3!
// Strict mode - error
"use strict"
function add(a, a) { // SyntaxError: Duplicate parameter name
return a + a
}
```
The `with` statement makes it impossible to know where variables come from at a glance:
```javascript
with (someObject) {
x = 10 // Is this someObject.x or a variable x? Depends on runtime!
}
```
This ambiguity prevents JavaScript engines from optimizing your code and makes bugs hard to track down. Use [destructuring](/concepts/modern-js-syntax) instead:
```javascript
const { x, y, z } = someObject // Clear and explicit
```
These words are reserved for potential future JavaScript features. Strict mode protects them so your code won't break when new syntax is added.
```javascript
"use strict"
let private = 10 // SyntaxError: Unexpected strict mode reserved word
let interface = {} // SyntaxError
```
Some of these words (like `static`) are already used in class definitions. Others may be used in future versions.