Skip to content
JavaScript js fundamentals 4 min read

Strict Mode

Strict mode is an opt-in variant of JavaScript that tightens the language’s rules so that mistakes which used to fail silently become real, visible errors. It was introduced in ES5 to clean up some of the language’s earliest design quirks without breaking the billions of pages relying on the old behavior. You turn it on with the literal string "use strict", and once you understand what it changes you’ll rarely want to write code without it.

Enabling strict mode

There are two ways to opt in. Place "use strict"; at the very top of a file to apply it to the entire script, or at the top of a function body to apply it only to that function. It must be the first statement — anything before it (other than comments) makes the directive a no-op string with no effect.

"use strict";

// Every line in this script now runs in strict mode.
function calculateTotal(items) {
  return items.reduce((sum, item) => sum + item.price, 0);
}

Function-scoped strict mode is useful when you can’t control the surrounding script:

function legacyApi() {
  // not strict here
}

function modernHelper() {
  "use strict";
  // strict only inside this function
}

Catching silent errors

The headline feature is that assignments which used to be quietly ignored now throw. The most common case is assigning to a variable you never declared. In sloppy mode that silently creates a global; in strict mode it’s a ReferenceError.

"use strict";

function setName() {
  userName = "Ada"; // forgot const/let
}

setName();

Output:

ReferenceError: userName is not defined

Without strict mode, userName would silently leak onto the global object — a classic source of bugs that only surface much later. Strict mode also makes writes to read-only and non-writable properties throw instead of failing silently.

"use strict";

const config = Object.freeze({ env: "production" });
config.env = "staging"; // TypeError, not a silent no-op

const obj = {};
Object.defineProperty(obj, "id", { value: 1, writable: false });
obj.id = 2; // TypeError

A few more cases that error under strict mode but are silent otherwise: deleting a non-deletable property, using a property name twice in a parameter list, and writing to a getter-only property.

How this changes in functions

In a plain function call (not a method, not new), sloppy mode sets this to the global object (window in browsers, globalThis in Node). Strict mode leaves this as undefined, which prevents accidental global mutation and makes bugs obvious.

"use strict";

function whoAmI() {
  return this;
}

console.log(whoAmI()); // undefined (would be the global object in sloppy mode)

This is one of the most valuable safeguards: a method detached from its object and called bare will now fail fast rather than silently scribbling on globals.

Modules and classes are always strict

You almost never need to type "use strict" in modern code, because the contexts where most code now lives are strict by default. ES module code — any file loaded with <script type="module">, an import/export, or a .mjs file in Node — is automatically strict. The bodies of class declarations and expressions are too.

// app.mjs — already strict, no directive needed
export function transfer() {
  amount = 100; // ReferenceError: amount is not defined
}
class Account {
  withdraw() {
    // class bodies are strict automatically
    balance -= 10; // ReferenceError if balance was never declared
  }
}

Tip: If you write import/export or class, you’re already in strict mode. The explicit "use strict" directive only matters for classic scripts and CommonJS files.

Sloppy vs strict at a glance

BehaviorSloppy modeStrict mode
Assign to undeclared variableCreates a globalReferenceError
Write to read-only / frozen propertySilently ignoredTypeError
Delete undeletable propertyReturns falseSyntaxError / TypeError
this in a plain function callGlobal objectundefined
Duplicate parameter namesAllowedSyntaxError
Octal literals like 0755AllowedSyntaxError
with statementAllowedSyntaxError

Warning: Strict mode is not retroactive — concatenating a strict file before a sloppy one can apply the directive to code that wasn’t written for it, or vice versa. Bundlers handle this per-module, but be careful when manually combining classic scripts.

Best practices

  • Prefer ES modules so strict mode is on automatically and you never have to think about it.
  • For any remaining classic scripts, add "use strict"; as the first line of the file.
  • Always declare variables with const or let; strict mode turns a forgotten declaration into an immediate error.
  • Treat a this of undefined as a signal that a method was called without its receiver — bind it or call it correctly rather than reverting to sloppy mode.
  • Don’t try to “fix” a strict-mode error by removing the directive; the error is pointing at a real bug.
  • When concatenating legacy scripts, keep each file’s mode self-contained to avoid one file’s directive bleeding into another.
Last updated June 1, 2026
Was this helpful?