JavaScript исторически очень снисходителен к ошибкам. Опечатался в имени переменной — язык молча создаст глобальную. Дважды объявил параметр в функции — молча возьмёт последний. Записал свойство в read-only-объект — молча проигнорирует. Это удобно для скриптов 1995 года, в которых нужно было всплывающее окно по клику, и неудобно для современных приложений, где такой «тихий пропуск» превращается в баг, который ловят неделю.

Чтобы дать разработчикам способ перейти на более строгое поведение языка не ломая обратную совместимость, в ES5 (2009) добавили строгий режим — директиву "use strict". Разберёмся, что именно она меняет, как её включают и почему в современном коде её всё чаще не пишут вообще — не потому что строгости больше не нужно, а потому что она и так подразумевается.

Как включить

Директива "use strict" — это просто строковый литерал, который JS-движок распознаёт как специальную команду. Включается на двух уровнях.

На весь файл. Директива должна быть первой исполняемой строкой:

"use strict";

const user = { name: "Anna" };
// весь дальнейший код выполняется в строгом режиме

В одной функции. Тогда строгий режим действует только внутри неё:

function strictHere() {
  "use strict";
  // код функции исполняется строго
}

function regular() {
  // тут поведение обычное
}

Главное правило: ничего исполняемого не должно стоять перед директивой. Комментарии — можно, обычные выражения — нет, иначе движок просто посчитает строку обычным выражением и проигнорирует.

Подводный камень с конкатенацией скриптов на сборке: если один файл с "use strict" в начале склеивается с другим, не строгим, директива в середине файла уже не сработает — она перестанет быть первой строкой. Поэтому при склейке либо включают строгий режим в каждом файле через функциональную форму, либо собирают через ES-модули, где об этом думать не нужно (см. ниже).

Что меняется

Изменений много, но они логично делятся на пять групп.

Тихие ошибки становятся настоящими

Самая полезная категория. То, что раньше молча проглатывалось, теперь бросает исключение — и баг видно сразу.

Использование необъявленной переменной. В обычном режиме создаст глобальную, в строгом — ReferenceError:

"use strict";

function setUser() {
  username = "Anna"; // ReferenceError: username is not defined
}
setUser();

Запись в read-only-свойство. В обычном режиме просто не сработает, в строгом — TypeError:

"use strict";

const config = {};
Object.defineProperty(config, "version", { value: 1, writable: false });

config.version = 2;
// TypeError: Cannot assign to read only property 'version'

Запись в свойство, у которого только getter. Та же история — TypeError вместо тишины:

"use strict";

const obj = {
  get count() { return 0; }
};
obj.count = 10;
// TypeError: Cannot set property count of #<Object> which has only a getter

Удаление переменной или функции. В обычном режиме delete просто вернёт false, в строгом — SyntaxError уже на этапе разбора.

Эта группа изменений тесно связана с темой встроенных типов ошибок — разбор каждого класса есть в отдельной статье про ошибки в JavaScript.

Запрет того, что «исторически случайно работало»

Конструкции, которые формально валидны в обычном JS, но в реальной работе только мешают.

Дублирование имени параметра. В обычном режиме игнорируется (берётся последний), в строгом — SyntaxError:

"use strict";

function add(num, num) {
  return num + num;
}
// SyntaxError: Duplicate parameter name not allowed in this context

Восьмеричные литералы со старым синтаксисом. Запись 012 в обычном режиме интерпретируется как восьмеричное число (десять, кстати, не двенадцать), что регулярно становится источником багов. В строгом — SyntaxError:

"use strict";

const wrong = 012;
// SyntaxError: Octal literals are not allowed

Современный явный синтаксис 0o12 работает в обоих режимах.

Оператор with. В обычном режиме можно открыть скоуп объекта и обращаться к его свойствам как к локальным переменным. На практике этот оператор не используется уже двадцать лет (он ломает статический анализ кода и непредсказуем для оптимизатора), а в строгом режиме просто запрещён:

"use strict";

with (Math) {
  console.log(sqrt(16));
}
// SyntaxError: Strict mode code may not include a with statement

Зарезервированные слова на будущее

Имена, которые могут стать ключевыми словами в будущих версиях стандарта, нельзя использовать как идентификаторы переменных:

"use strict";

const package = "init"; // SyntaxError
const interface = {};   // SyntaxError

Полный список: implements, interface, package, private, protected, public, static, yield. В обычном режиме их использовать можно, но не нужно — завтра они официально станут зарезервированными, и весь такой код придётся переписывать.

Поведение this

Одно из самых заметных изменений в реальной жизни. В обычной (не методной) функции в обычном режиме this ссылается на глобальный объект (window в браузере). В строгом — на undefined:

"use strict";

function whoAmI() {
  console.log(this);
}
whoAmI(); // undefined (в обычном режиме было бы window)

На первый взгляд изменение мелкое — пока не натыкаешься на классический pitfall с потерей контекста. Метод объекта, переданный как callback, отвязывается от своего владельца:

"use strict";

const counter = {
  value: 0,
  increment() {
    this.value++; // в callback this будет undefined
  }
};

button.addEventListener("click", counter.increment);
// TypeError: Cannot read properties of undefined (reading 'value')

В обычном режиме та же ошибка случилась бы тише: this бы стал window, скрипт бы создал глобальное свойство window.value и продолжил работу — и баг бы пришлось ловить по симптомам. Решения стандартные: counter.increment.bind(counter) или стрелочная функция-обёртка () => counter.increment(). Подробный разбор поведения this — в отдельной статье про ключевое слово this.

eval и arguments под контролем

Две исторически проблемные конструкции в строгом режиме ведут себя предсказуемо.

eval не загрязняет внешний скоуп. В обычном режиме переменные, объявленные внутри eval(...), видны снаружи. В строгом — нет:

"use strict";

eval("var secret = 42;");
console.log(secret); // ReferenceError: secret is not defined

arguments.caller и arguments.callee запрещены. Эти свойства давали доступ к стеку вызовов из тела функции и часто использовались для рекурсии в анонимных функциях. В строгом режиме обращение к ним бросает TypeError. Альтернатива — именованные функциональные выражения.

Где строгий режим включён по умолчанию

Самое важное про современный JavaScript: писать "use strict" вручную сейчас обычно не нужно. В нескольких контекстах строгий режим действует автоматически:

  • Модули ES6 (<script type="module"> или импортируемые через import) — всегда исполняются строго.
  • Тело любого class — и в объявлении, и в выражении класса.
  • Тело тегированного шаблонного литерала.

Поскольку любой современный фронтенд-проект на Vite, webpack или esbuild собирается из модулей, фактически весь его код — уже в строгом режиме. Директиву писать просто незачем; собиратели её часто и сами вырезают как избыточную.

Когда явная директива всё ещё нужна

Случаев осталось немного:

  • Старый сайт, в котором скрипты подключаются обычным <script> без type="module".
  • Inline-скрипты внутри HTML, где нет шанса пометить их как модули.
  • Утилитарные библиотеки, которые публикуются в формате IIFE и должны работать как в строгом, так и в обычном окружении предсказуемо.

Во всех этих случаях директива в начале файла или в начале IIFE-обёртки — разумная страховка.

Чего строгий режим НЕ делает

Нездоровая часть популярности директивы — ожидания, которые она не оправдывает. Чтобы не было разочарований:

  • Не ускоряет код. Историческая байка про «двухкратный прирост» не подтверждалась бенчмарками никогда. Современные движки оптимизируют оба режима одинаково.
  • Не проверяет типы. Это не TypeScript. Передавать строку туда, где ждут число, в строгом режиме всё ещё разрешено, и если методу повезёт сработать — никакой ошибки не будет.
  • Не лечит async-проблемы. Race conditions, забытые await, утечки промисов — всё это вне зоны ответственности строгого режима.
  • Не делает код «безопасным» в смысле web security. XSS, CSRF, injection-атаки — ортогональны.

Строгий режим — это просто более требовательный парсер и более строгий рантайм. Полезный, но узкоспециализированный инструмент.

Итог

Директива "use strict" когда-то была важным переключателем между «старым» и «современным» JavaScript. В 2026 году она во многом ушла на второй план: модули и классы строги по умолчанию, и любой проект на современном бандлере живёт в строгом режиме без явных директив. Но знать, что именно меняется, всё ещё полезно — и чтобы понимать, почему опечатка в имени переменной бросает ReferenceError, и чтобы не наступать на pitfall с потерей this, и чтобы при работе с legacy-кодом без модулей вспомнить о паре строк, которые превратят тихие баги в видимые исключения.