Суворий режим у JavaScript
Strict mode (суворий режим) — це режим JavaScript, увімкнений директивою "use strict";, який змушує рушій кидати помилки там, де він зазвичай мовчки проковтне їх.
Теорія
TL;DR
- Уяви систему попереджень компілятора: звичайний JS запустить сумнівний код без слова, strict mode зупинить одразу.
- Головна різниця: без суворого режиму присвоєння до неоголошеної змінної створює глобальну; з ним отримуєш
ReferenceError. thisвсередині звичайної функції повертаєundefined, а неwindowчиglobal.- ES6 модулі вже суворі за замовчуванням. Директива не потрібна.
- Додавай до кожного нового файлу. Єдиний виняток: скрипти для IE9 і старших.
Швидкий приклад
// Без strict mode - створює глобальну змінну без жодної помилки
function calcTotal(price) {
subtotal = price * 1.1; // Нема помилки, але забруднює глобальну область
return subtotal;
}
// З strict mode - зупиняє одразу в місці проблеми
"use strict";
function calcTotal(price) {
subtotal = price * 1.1; // ReferenceError: subtotal is not defined
return subtotal;
}Перша версія працює і тихо отруює глобальний об'єкт. Друга зупиняє рівно там, де проблема, а не через три функції після, коли щось ламається в непов'язаному місці.
Що саме змінює strict mode
Коли рушій зустрічає "use strict";, він переходить у суворий режим парсингу для поточної та всіх дочірніх областей видимості. Ще під час компіляції, до виконання, він відмічає вісімкові літерали (008), дублікати параметрів і оператор with як SyntaxError. Під час виконання присвоєння до неоголошеної змінної дає ReferenceError, а delete на ідентифікаторі змінної кидає SyntaxError.
Те, що найчастіше збиває з пантелику: this всередині звичайного виклику функції стає undefined. У звичайному режимі він за замовчуванням вказує на глобальний об'єкт (window у браузері). Ця поведінка відповідає за цілий клас помилок, де думаєш що пишеш в об'єкт, а насправді в глобальну область.
Коли вмикати
- Новий файл або проект:
"use strict";зверху. Жодних мінусів. - Legacy кодова база: додавай пофайлово або пофункційно. Можна мігрувати поступово.
- ES6 модулі (
.mjsабоtype="module"): вже суворі. Директива зайва. - Сторонні скрипти, які не контролюєш: огорни свій код у суворе IIFE замість глобального strict.
- Реальний виняток: скрипти для IE9 і давніших.
Як це обробляє рушій
V8 у Chrome і Node.js застосовує агресивніші JIT-оптимізації до суворого коду. Причина: немає with, щоб ускладнити резолюцію scope, немає неявних глобальних змінних, передбачуваний this. У Node.js є прапор --use-strict для глобального увімкнення. Babel і webpack додають "use strict" автоматично при транспіляції через @babel/preset-env.
Поширені помилки
Вважати, що strict на рівні функції впливає на того, хто її викликає:
function parent() {
x = 1; // Без помилки - parent у звичайному режимі
}
function child() {
"use strict";
y = 2; // ReferenceError - child у суворому режимі
}Strict mode діє лише на свою область видимості. Батьківська функція залишається сліпою до помилок. Це плутає в кодових базах, де лише частина файлів має директиву.
Спроба видалити змінну через delete:
"use strict";
var total = 100;
delete total; // SyntaxError: Delete of an unqualified identifier in strict modeУ звичайному режимі delete на змінній мовчки повертає false. У суворому - це SyntaxError.
Думати, що eval() наслідує strict mode:
"use strict";
eval("x = 1"); // Все одно забруднює глобальну область
// Виправлення:
eval('"use strict"; x = 1;');Типова проблема в Node.js, яка регулярно з'являється на співбесідах.
Дублікати імен параметрів:
"use strict";
function add(a, a) { // SyntaxError ще до запуску коду
return a + a;
}Звичайний режим приймає це без слова. Strict mode відловлює на етапі парсингу.
Де зустрічається в реальних проектах
- React: Babel додає
"use strict"до кожного транспільованого файлу через@babel/preset-env. - Node.js: вбудовані модулі типу
fsвикористовують strict mode всередині. Твійapp.jsтеж повинен. - Express: продакшн-стартери вмикають strict на рівні файлу, щоб не було глобальних витоків у route handler'ах.
- Lodash: strict mode з версії 4.0, що прибрало цілий клас проблем з prototype.
- jQuery: v3+ працює у суворому режимі.
Я бачив, як глобальні витоки змінних з Express route handler'ів призводили до memory issues в Node.js у production. Strict mode відловив би ті присвоєння під час запуску, а не через три тижні на постмортемі.
Follow-up питання
Q: Що відбувається з this у звичайній функції в strict mode?
A: Стає undefined замість глобального об'єкту. Тому this.name = "x" всередині такої функції кидає TypeError, замість того щоб мовчки додати name до window.
Q: Як увімкнути strict mode в ES6 модулях?
A: Не потрібно. Всі ES6 модулі суворі за замовчуванням. Тіла класів теж.
Q: Назви три речі, які забороняє strict mode.
A: Вісімкові літерали (08), дублікати імен параметрів і оператор with. Також видалення змінних і присвоєння до неоголошених змінних.
Q: Чи можна поєднувати суворий і звичайний режими в одному проекті?
A: Так. Strict mode діє на свій scope. Звичайна функція, яка викликає суворі, залишається звичайною зі свого боку. Помилка вважати, що strict піднімається вгору до того, хто викликає.
Q: Чи впливає strict mode на продуктивність?
A: Трохи позитивно. V8 застосовує агресивніші JIT-оптимізації в суворому коді через менше крайніх випадків при резолюції scope. Ефект невеликий, але реальний.
Приклади
Базовий: перевірка оголошення змінних
"use strict";
function processOrder(amount) {
// Без оголошення це б мовчки стало глобальною змінною
total = amount * 1.2; // ReferenceError: total is not defined
return total;
}
processOrder(100);Помилка вказує точно де пропущений const або let. Без strict mode total опинився б на window і довелося б шукати його по кількох файлах.
Середній: this у відчепленому виклику функції
"use strict";
const obj = {
name: "strictObj",
method() {
// Стрілкова функція: this лексично прив'язаний до obj
return () => this.name;
},
looseMethod() {
// Звичайна функція: this залежить від способу виклику
return function() { return this.name; };
}
};
console.log(obj.method()()); // "strictObj" - стрілка зберігає this
console.log(obj.looseMethod()()); // undefined у strict mode (window.name у звичайному)looseMethod повертає звичайну функцію без отримувача. Звичайний режим дає їй window. Strict mode робить undefined, що робить баг видимим одразу, а не ховає його за глобальним об'єктом.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.