JavaScript создавался как язык для простых скриптов на веб-страницах. Никто не думал, что много лет спустя он станет одним из самых используемых языков для разработки веб-приложений. Поэтому изначальный JavaScript позволял некоторые вольности и допущения, которые были некритичны, но упрощали работу. Со временем в языке появлялись новые функции, а все изначальные неудачные решения сохранялись.
В 2009 году появился стандарт ECMAScript 5 (ES5). Его важной особенностью было добавление «строгого режима», который ограничивает гибкие, но потенциально опасные возможности языка. Разбираемся, как он работает.
Что такое use strict mode и как его включить
По умолчанию код в JS выполняется в sloppy mode (небрежном режиме). С одной стороны, это даёт гибкость и позволяет писать более свободный код. Например, можно использовать переменную до её объявления. С другой стороны, это может приводить к неожиданному поведению кода и проблемам с безопасностью приложений. Но если включить строгий режим, то ошибки выполнения не будут игнорироваться, что поможет при отладке.
В строгом режиме нельзя:
- использовать переменные без их объявления;
- дублировать имена свойств в объектах;
- дублировать параметры функций;
- удалять переменные, функции и аргументы;
- использовать зарезервированные слова;
- использовать устаревшие конструкции;
Также строгий режим меняет поведение объекта this
в функции.
👉 Чтобы строгий режим работал по всему коду, нужно добавить директиву 'use strict'
в начале скрипта до других команд:
// включаем строгий режим
"use strict";
// дальнейший код обрабатывается в строгом режиме
Перед директивой 'use strict'
можно писать только комментарии. Когда строгий режим включён, отключить его для файла уже нельзя.
👉 Чтобы строгий режим работал только в одной функции, нужно добавить директиву 'use strict'
в начало тела функции. Это не повлияет на остальной код вне этой функции:
function strictModeFunction() {
"use strict";
// код внутри этой функции будет выполняться в строгом режиме
x = 3.14;
console.log(x);
}
function nonStrictModeFunction() {
// код здесь продолжает выполняться в обычном режиме
y = 3.14;
console.log(y);
}
strictModeFunction()
nonStrictModeFunction()
Выполнение функции strictModeFunction
выдаёт ошибку, поскольку мы использовали переменную без её объявления. В обычном режиме эта ошибка игнорируется
В современном коде редко можно встретить явное объявление строгого режима. Дело в том, что инструменты сборки — Webpack и Babel — часто автоматически включают директиву 'use strict'
в код. А во фреймворках или библиотеках (Angular или React) строгий режим уже включён по умолчанию.
Теперь посмотрим на примерах, как строгий режим меняет поведение кода.
Ограничения строгого режима
Нельзя использовать переменные без их объявления: перед использованием переменной обязательно нужно объявить её через var
, let
или const
, иначе мы получим ошибку ReferenceError
.
"use strict";
function calculateArea(radius) {
area = Math.PI * radius * radius;
console.log(area);
}
calculateArea(5);
В этом примере мы пытались рассчитать площадь круга, используя радиус, переданный в функцию. Но поскольку переменная area
не была объявлена, консоль выдаёт ошибку ReferenceError
:
В нестрогом режиме такое присвоение привело бы к созданию глобальной переменной area
, которая автоматически стала бы свойством глобального объекта (window
в браузерах). Глобальный объект доступен из любого места кода.
В больших приложениях это может привести к конфликтам, где одно и то же имя переменной может использоваться в разных частях программы: переменные будут перезаписывать значения друг друга. Использование строгого режима предотвращает случайное создание глобальных переменных и помогает избежать ошибок, связанных с областью видимости переменных.
Нельзя дублировать параметры функции: в строгом режиме объект не может иметь два свойства с одинаковыми именами. Попытка это сделать приведёт к SyntaxError
.
"use strict";
function createUser(name, age, name) {
console.log(`Создан пользователь: ${name}, Age: ${age}`);
}
В этом примере функция createUser
принимает имя и возраст пользователя. Параметр name
указан дважды. В обычном режиме значение параметра было бы перезаписано значением последнего указанного параметра с таким же именем. То есть все предыдущие значения для этого параметра были бы утеряны, и в теле функции использовалось бы только последнее значение.
В строгом режиме это сразу же приведёт к SyntaxError
, и функция не будет выполняться:
В крупных проектах можно не уследить за всеми параметрами функций, и такие промахи в обычном режиме приведут к неожиданному поведению кода.
Нельзя удалять переменные, функции и аргументы: оператор delete
не может удалять переменные, функции или аргументы функций. Если попробовать их удалить, возникнет SyntaxError
.
"use strict";
let x = 1;
delete x;
Мы объявили переменную x
через let
, тут же попытались её удалить и получили ошибку:
В обычном режиме оператор delete
используется для удаления свойств из объектов. Если мы удаляем свойство объекта, а затем пытаемся получить доступ к этому свойству, программа вернёт значение undefined
, поскольку свойства больше нет в объекте. Это может привести к ошибкам, если код ожидает, что свойство всё ещё будет доступно.
В строгом режиме delete
может использоваться только для удаления свойств объектов, а не локальных переменных, которые могут быть важны для выполнения кода.
Нельзя использовать зарезервированные слова: это слова implements
, interface
, let
, package
, private
, protected
, public
, static
и yield
, которые могут быть использованы в будущих версиях JavaScript. Ограничение помогает избегать конфликтов и ошибок в коде, когда в язык добавляются новые функции.
Нельзя использовать устаревшие конструкции: строгий режим ограничивает использование некоторых устаревших или потенциально опасных конструкций: with
и eval
.
Инструкция with
расширяет область видимости текущего блока кода и включает в неё свойства указанного объекта. Это позволяет обращаться к свойствам объекта напрямую, без необходимости упоминать имя объекта. Например, мы создали объект pet
и задали ему два свойства:
let pet = {
name: "Себастиан",
breed: "Ретривер",
};
С помощью with
мы можем обратиться к каждому свойству, не указывая имя объекта при каждом вызове:
with(pet){
// эквивалентно console.log(pet.name)
console.log(name);
// эквивалентно console.log(pet.breed)
console.log(breed);
}
С одной стороны, мы пишем меньше кода, с другой, это может вызвать неоднозначности, если во внешнем контексте есть переменные с такими же именами. Инструкция with
меняет область видимости текущего блока кода и в целях безопасности в строгом режиме отключена.
Тот же запрет относится и к функции eval()
, которая позволяет выполнить код, представленный в виде строки. В обычном режиме код eval('let x')
приведёт к объявлению переменной x
. Это позволяет скрывать объявления переменных в строках, что может привести к перезаписи определений тех же переменных, находящихся за пределами eval
.
В строгом режиме нельзя объявлять переменные в коде, который передаётся в виде строки в eval()
. Однако консоль Chrome выдаст ошибку даже без явного включения строгого режима:
Объект this
в функции ведёт себя по-другому: в обычном режиме значение this
внутри функции по умолчанию равно глобальному объекту. Такое поведение может привести к потенциально опасным изменениям в глобальном объекте, когда функция ошибочно изменяет его свойства.
Допустим, мы в обычном режиме создали функцию и внутри неё присвоили значение Updated
свойству data
объекта, на который указывает this
.
function updateData() {
this.data = "Обновлено";
}
После этого мы вызываем функцию без контекста, то есть явно не указываем объект, который должен служить значением this
внутри этой функции.
updateData();
Когда updateData()
выполняется, то изменяет свойство data
глобального объекта window
, поскольку this
по умолчанию ссылается именно на него. Чтобы это проверить, вызовем свойство объекта window
:
console.log(window.data);
Такое изменение может повлиять на другие части программы, если они тоже используют глобальный объект. В результате код станет непредсказуемым.
В строгом режиме, если функция вызывается без контекста, то this
будет undefined
. Попытка доступа или изменения свойства data
на undefined
приведёт к ошибке TypeError
:
Когда использовать строгий режим?
Строгий режим делает код безопаснее и быстрее. Хотя его использование необязательно, всё же стоит его включать, чтобы избежать распространённых ошибок и приучить себя писать чистый и безопасный код. Кроме того, это подготовит к работе с современными фреймворками и проектами, где строгий режим часто используется по умолчанию.