Strict mode в JavaScript

Строгий режим (Strict mode) современного JavaScript не позволяет использовать старый "неаккуратный" режим JavaScript с игнорированием некоторых ошибок в коде, вследствие чего код может запускаться с неожиданными результатами.

Strict mode изменяет как допустимый синтаксис кода, так и поведение кода во время выполнения, что влияет на появление в коде ошибок синтаксиса или ошибок выполнения, которые ранее пропускались движком в обычном режиме.

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

Строгий режим применим как к отдельным функциям, так и к целому скрипту, однако его нельзя применять к операторам и другим блокам, заключенным в фигурные скобки.

Включение строгого режима производится размещением специальной директивы "use strict" (или 'use strict'):

  1. на первой строке скрипта - режим включается для всего скрипта;
  2. в начале функции (после открывающей фигурной скобки) - режим включается для кода функции, включая вложенные функции.

Примеры

Строгий режим в функции:

Строгий режим в стрелочной функции:

[свернуть]

Особенности использования строгого режима (Strict mode) в JavaScript:

  1. При объединении со скриптами, использующими строгий режим, скрипты, которые его не используют, начинают его использовать, и наоборот: объединение обычного скрипта со строгим выглядит как нестрогий скрипт. 
  2. Отменить строгий режим невозможно (нет никакой отменяющей директивы, которая возвращала бы движок к старому поведению). 
  3. В структурах современного JavaScript ("классах" и "модулях")  строгий режим включается автоматически, поэтому в них добавлять директиву "use strict" не нужно.

Появление в коде JavaScript ошибок синтаксиса или ошибок выполнения при включении строгого режима

В обычном (нестрогом) режиме на некоторые допустимые ошибки JS никак не реагирует. Строгий режим ограничивает использование ошибочного синтаксиса и не позволяет коду запускаться с ошибками в случаях:

  • создания глобальных переменных;
  • удаления защищенных свойств объекта;
  • использования неуникальных имен параметров функции;
  • использования восьмеричной записи чисел;
  • использование синтаксиса, усложняющего оптимизацию (например, при использовании оператора with);
  • объявлении переменных внутри оператора eval;
  • попыток удаления простых имен переменных.
Запрет создания глобальных переменных

Так, строгий режим предотвращает создание глобальных переменных, например, код ниже вызовет ReferenceError:

Таким образом, в строгом режиме указанный выше код не запустится: глобальную переменную globalVariable можно создать только при выключенном строгом режиме, который предотвращает случайное создание глобальных переменных.

Кроме того, в строгом режиме нельзя присваивать значения:

  • переменным только для чтения (например, arguments, NaN или eval);
  • защищенным от записи глобальным переменным (undefined и Infinity);
  • защищенным от записи свойствам объектов (свойствам только для геттеров) и свойствам нерасширяемых объектов.

Примеры отсюда

[свернуть]
Попытка удалить защищенные свойства объекта

При попытке удалить защищенные свойства объекта появится исключение TypeError, например:

[свернуть]
Неуникальные имена параметров функции

В строгом режиме имена параметров функции должны быть уникальны. В обычном же режиме, если у двух параметров одинаковое имя, определенное позже имя будет принято как значение параметра при передаче аргументов. Поэтому следующий пример выдаст синтаксическую ошибку:

[свернуть]
Ошибка использования восьмеричной записи чисел

В строгом режиме восьмеричная запись чисел не разрешена.

Она не является частью спецификации, но поддерживается в браузерах добавлением 0 к восьмеричным числам. Это сбивает разработчиков с толку, так как некоторые думают, что 0 перед числом ничего не значит.

[свернуть]
Использование синтаксиса, усложняющего оптимизацию

Строгий режим предотвращает использование синтаксиса, усложняющего оптимизацию. Один из примеров — это оператор with, при использовании которого интерпретатор JavaScript не знает, на какую переменную или свойство вы ссылаетесь, поскольку переменная с тем же именем может быть внутри или снаружи оператора with.

Использование оператора with не рекомендуется.

Например:

JavaScript не сможет определить x внутри оператора with ссылается на переменную x или свойство obj.x. Следовательно, расположение x в памяти неоднозначно. Поэтому строгий режим запрещает использование оператора with.

[свернуть]
Объявление переменных внутри оператора eval

Следующая вещь, имеющая особенности в строгом режиме — это объявление переменных внутри оператора eval.

Использование оператора eval не рекомендуется, он считается устаревшим.

Например, без строгого режима eval('let x') объявит переменную x внутри кода. Это позволяет прятать объявление переменных в строках, что может блокировать объявление той же переменной вне оператора eval. Чтобы предотвратить это, строгий режим не позволяет объявлять переменные в аргументе строки, который мы передаем внутрь оператора eval.

Подробнее...

[свернуть]
Попытка удаления простых имен переменных

Строгий режим также запрещает удаление простых имен переменных, поэтому код ниже выдаст синтаксическую ошибку:

[свернуть]
Запрет неверного синтаксиса метода eval и объекта argument

Неверный синтаксис метода eval и объекта argument не разрешен в строгом режиме.

Например, им нельзя задать новые значения или использовать их как имена переменных, функций или параметров функций. Вот пример неверного использования eval и argument (отсюда):










Строгий режим не разрешает создавать псевдоним для объекта arguments и задавать с ним новые значения.

Рассмотрим пример:

Без строгого режима, если параметр функции — a, тогда присвоение внутри функции переменной a некоторого значения также присваивает значение arguments[0]. В строгом режиме параметр a  и переменная a внутри функции различаются (у объекта arguments всегда будет список аргументов, с которыми вызывается функция).

Например:

  • в обычном (нестрогом) режиме:

  • в строгом режиме:

[свернуть]

Оптимизация производительности JavaScript в строгом режиме

1. Запрет arguments.callee

Подробнее о arguments.callee

В обычном режиме arguments.callee возвращает имя функции с arguments.callee внутри. Например:

Это мешает оптимизациям, например, встроенным функциям, потому что arguments.callee требует, чтобы при его вызове была доступна ссылка на невстроенную функцию. Поэтому теперь в строгом режиме arguments.callee вызывает TypeError:

[свернуть]
2. Ключевое слово _this в строгом режиме

В обычной функции this всегда представляет собой объект:

  • либо это непосредственно объект, в случае вызова с this представляющим объект-значение;
  • либо значение, упакованное в объект, в случае вызова с this типа Boolean, string, или number;
  • либо глобальный объект, если тип this это undefined или null.

При этом автоматическая упаковка снижает производительность. Кроме того, когда обычная функция находится в глобальной области видимости, ключевое слово this, использованное в ней, будет привязано к объекту window, что делает видимым глобальный объект и является угрозой безопасности, потому что глобальный объект предоставляет доступ к функциональности, которая должна быть ограничена в среде "безопасного" JavaScript.

Для точного определения конкретного this  необходимо использовать callapply, или bind.

Однако если функция выполняется в строгом режиме, то в this будет записано undefined, так как в этом режиме запрещены привязки по умолчанию. 

Сравните:

Таким образом значение, передаваемое в функцию как this, в строгом режиме не приводится к объекту (не "упаковывается"), т.е. для функции в строгом режиме точно определённый this не упаковывается в объект, а если не определён точно, this является undefined.

Если this функции связан call, apply или bind с любыми необъектными типами, такими как примитивные типы undefined, null, number, boolean и так далее, они будут принудительно приведены к объекту:

Все журналы консоли будут иметь значение true, так как this внутри функции в строгом режиме не преобразуется автоматически в глобальный объект window.

[свернуть]

Исправления безопасности в режиме strict mode

В строгом режиме caller и arguments представляют собой неудаляемые свойства, которые приведут к вызову исключения при попытке их чтения или записи:

Потенциальная дыра в безопасности устраняется запретом доступа к этим двум свойствам функции. В строгом режиме в примере выше мы не сможем получить доступ к restricted.caller и restricted.arguments и использовать их для получения стека функций. При выполнении код выдаст TypeError.

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.