Strict Mode: Every Restriction & V8 Performance Wins
'use strict' — V8 ko bol do ki ab registers mein rakho parameters. Speed milti hai.
'use strict' — three words. Three words that put V8 into a completely different execution mode. Strict mode isn't just about restrictions — it's a performance contract with the engine. When V8 knows there are no accidental globals, no arguments aliasing, no with statement — it can make optimizations impossible in sloppy mode.
// File-level strict mode
'use strict'; // ← must be first statement
// Everything in this file is now strict
// Function-level strict mode
function strictFunc() {
'use strict'; // ← only this function is strict
// ...
}
// Class body — ALWAYS strict (no directive needed)
class MyClass {
method() {
// strict mode — always, no directive needed
console.log(typeof this); // 'object' or 'undefined' (not window)
}
}
// ES6 module — ALWAYS strict
// import './something'; // this file is auto-strict
// What counts as "first statement":
'use strict'; // ✅ — first statement
// comments above are OK
/* multi-line comment OK */
'use strict'; // ✅ — still first real statement
var x = 1;
'use strict'; // ❌ — NOT first statement — ignored silently!
Here is every restriction strict mode enforces. Know them all — interviews love this list:
'use strict';
// 1. No accidental globals
function noGlobals() {
'use strict';
leaked = 'oops'; // ReferenceError: leaked is not defined
// In sloppy mode: window.leaked = 'oops' — silent pollution!
}
// 2. No duplicate params
// function dup(a, a) { } // SyntaxError: Duplicate parameter name
// 3. this in plain function call = undefined
function showThis() {
'use strict';
console.log(this); // undefined — not window!
}
showThis();
// 4. arguments not aliased
function noAlias(x) {
'use strict';
arguments[0] = 99;
console.log(x); // still the original value — NOT 99!
// In sloppy: x would change to 99 (aliased to arguments[0])
}
noAlias(1); // x is 1, not 99
// 5. delete restrictions
var obj = {};
Object.defineProperty(obj, 'fixed', { configurable: false, value: 1 });
// delete obj.fixed; // TypeError: Cannot delete property (strict)
var x = 1;
// delete x; // SyntaxError: Cannot delete variable 'x'
// 6. No octal
// var n = 010; // SyntaxError: Octal literals are not allowed
var n = 0o10; // ✅ use 0o prefix for octal
console.log(n); // 8
Strict mode isn't just about catching bugs — it makes your code genuinely faster. Here are the five V8 performance wins:
Win 1: Parameters in CPU registers — no arguments aliasing means V8 can put params in registers. In sloppy: params and arguments[] must stay in sync on the stack. In strict: arguments[] not aliased — params go to CPU registers (much faster).
Win 2: Function inlining — no arguments.callee means the function can be inlined by TurboFan. arguments.callee prevents inlining because the inlined copy has no self-reference.
Win 3: No with statement — V8 knows all variable locations at compile time. No dynamic scope injection.
Win 4: Faster this check — this === undefined is a fast comparison, not a window object lookup.
Win 5: Fewer deoptimization triggers — strict mode has fewer dynamic scope scenarios that cause V8 to bail out of optimized code.
// Performance difference — measurable in tight loops
// SLOPPY MODE (default) — parameters on stack
function sloppyAdd(a, b) {
// V8 must maintain: a on stack, arguments[0] = a (aliased!)
// Cannot put a or b in CPU registers safely
return a + b;
}
// STRICT MODE — parameters can go to registers
function strictAdd(a, b) {
'use strict';
// V8 knows: arguments[0] is NOT aliased to a
// a and b can live in CPU registers EAX, EBX
// No stack read needed — registers are fastest possible
return a + b;
}
// Benchmark:
console.time('sloppy');
let s = 0;
for (let i = 0; i < 10000000; i++) { s += sloppyAdd(i, 1); }
console.timeEnd('sloppy');
console.time('strict');
let t = 0;
for (let i = 0; i < 10000000; i++) { t += strictAdd(i, 1); }
console.timeEnd('strict');
// strict is faster — parameter register allocation
arguments.callee was a way for an anonymous function to reference itself — used primarily for anonymous recursion. arguments.caller (non-standard) referenced the calling function. Both are banned in strict mode.
Why banned: arguments.callee prevents function inlining. TurboFan cannot inline a function that references itself via callee — the callee reference must remain valid after inlining, which it wouldn't be. By banning callee, V8 is free to inline aggressively.
// OLD: anonymous recursion via arguments.callee (sloppy only)
var factorial = function(n) {
if (n <= 1) return 1;
return n * arguments.callee(n - 1); // calls "current function"
// In strict mode: TypeError: 'caller', 'callee', and 'arguments'
// properties may not be accessed on strict mode functions
};
console.log(factorial(5)); // 120 (sloppy mode only)
// FIX: named function expression — works everywhere including strict
var factorial = function fact(n) {
'use strict';
if (n <= 1) return 1;
return n * fact(n - 1); // 'fact' is the name — accessible inside!
};
console.log(factorial(5)); // 120 ✅
// 'fact' is NOT accessible OUTSIDE:
// console.log(fact); // ReferenceError — name is only inside
// Arrow function recursion via outer variable
const fib = (n) => n <= 1 ? n : fib(n-1) + fib(n-2);
// Captures 'fib' from outer scope via closure — works in strict
// Why inlining matters:
// arguments.callee prevents inlining because the inlined copy
// has no "self reference" — the callee reference would be wrong.
// Without callee, V8 can inline the entire function body at the
// call site — eliminating function call overhead in hot loopsMost modern JavaScript contexts are automatically strict — you rarely need the directive yourself:
// Modern code — strict is automatic in most contexts:
// ES6 Class — always strict
class Calculator {
add(a, b) { return a + b; } // strict, no directive
}
// ES Module — always strict
// math.js:
// export const add = (a, b) => a + b; // strict, auto
// TypeScript — always compiles to strict mode
// (tsconfig.json: "strict": true is additional TS checks on top)
// Node.js CommonJS — NOT automatic, add manually:
// utils.js (CommonJS):
'use strict'; // ← needed here!
const add = (a, b) => a + b;
module.exports = { add };
// Node.js ESM — automatic:
// utils.mjs or package.json "type": "module"
// export const add = (a, b) => a + b; // auto-strict
// The practical checklist:
// Writing a .js file with require/module.exports? Add 'use strict'
// Writing a .js file with import/export? Already strict
// Writing a class? Already strict
// Writing TypeScript? Already strict
// Using a modern bundler (Vite, Webpack)? Usually strict
// ESLint config to enforce:
// "rules": { "strict": ["error", "global"] } for CJS
// "rules": { "strict": ["error", "never"] } for ESM (already strict)
Lo kar liya — Stage 4 Complete!
- ✅ 'use strict' must be the FIRST statement — after any code, it's silently ignored
- ✅ ES modules and class bodies are automatically strict — no directive needed
- ✅ Key restrictions: no accidental globals, no duplicate params, no with, this=undefined in plain calls, no arguments aliasing
- ✅ V8 performance win: strict mode allows parameters in CPU registers because arguments aliasing is eliminated
- ✅
arguments.calleeprevents function inlining — banned in strict mode. Use named function expressions instead - ✅ Modern code: TypeScript, ES modules, and class bodies are all already strict —
'use strict'only needed in CommonJS Node.js files
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login