JavaScript Strict Mode
В пятой редакции ECMAScript был представлен строгий режим (далее в статье Strict Mode). Strict Mode накладывает слой ограничений на JavaScript, он отгораживает вас от опасных частей языка (те части, которые есть исторически, но лучше чтобы их не было) и позволяет снизить вероятность ошибки.
Пока читал эту статью я написал 38 тестов, покрывающих все правила Strict Mode, объявленные в спецификации ES5. Вы можете посмотреть насколько ваш браузер поддерживает эти справила вот тут.
Код каждого теста представлен в конце статьи, чтобы помочь вам лучше понять спецификацию. Вы также можете выполнить тест вручную, скопируя код в консоль. Весь исходный код находится в моем репозитории.
Firefox 4 уже полностью поддерживает Strict Mode, а Chrome 11 практически полностью. Strict Mode уже не за горами — давайте изучим его подробнее!
Как включить Strict Mode?
Если добавить «use strict» в начало вашего JavaScript кода, то Strict Mode будет применен для всего кода:
В качестве альтернативы вы можете включить Strict Mode только в отдельной функции, добавив «use strict» в начало тела вашей функции:
Наследуют ли внутренние функции Strict Mode от внешних функций?
Внутренняя функция, объявленная внутри внешней, в которой включен Strict Mode тоже будет иметь Strict Mode:
Важно запомнить, что Strict Mode не распространяется на «нестрогие» (ориг. non-strict) функции, которые выполняются внутри строгой функции (или они отправлены в функцию в качестве аргументов или выполняются, используя call или apply):
Почему я не могу включить Strict Mode в консоли моего браузера?
Когда выполняешь код в консоли фаербага или в других консолях использование «use strict» вне функции не имеет силы. Это потому, что большинство консолей обрамляют ваш код в eval’ом, поэтому ваш «use strict» не является первым выражением. Это можно обойти, обрамив ваш код в замыкание (IIFE), в начало которого мы положим «use strict» (но, когда я тестировал такой способ включения Strict Mode я понял, что это довольно неудобно, особенно если работать в консоли webkit developer tools — лучше тестировать ваш код на странице):
Что произойдет если мой браузер не поддерживает Strict Mode?
Ничего. Директива «use strict» это обычное строковое выражение, которое будет проигнорировано всеми движками JavaScript, которые не поддерживают Strict Mode. Это позволяет безопасно использовать синтаксис Strict Mode во всех браузерах без каких-либо опасений, в то время когда браузеры имеющие поддержку Strict Mode будут использовать его.
Какие правила включены в Strict Mode?
Правила определены в спецификации Strict Mode и включают в себя ограничения во время «компиляции» и интерпретации (выполнения скрипта). Это вводный обзор (каждое правило я описал с примерами в следующем параграфе): ecma262-5.com/ELS5_HTML.htm#Annex_C
Синтаксические ошибки Syntax Errors
В большинстве случаев Strict Mode предотвращает выполнение подозрительного или нелегального кода в процессе загрузки. Восьмеричные числа, дубли имен переменных, некорректное использование delete и попытки сделать что-нибудь этакие с eval и ключевым словом arguments, использование with приведет к исключению SyntaxError.
Слово this
В Strict Mode объект this не будет корректироваться. Это возможно самая интересная часть Strict Mode и самая тяжелая(шокирующая) для разработчиков. Все знают, что если первый аргумент call или apply — null или undefined, то значение this выполняемой функции будет преобразование в глобальный объект (для браузеров это window).
Прямое создание глобальных переменных
Не все согласятся с этим, но непрямое создание глобального объекта почти всегда является ошибкой. В Strict Mode вам выдадут красную карточку — ReferenceError.
arguments.caller и arguments.callee
Эти «полезные свойства» (от пер. никогда не применял их) запрещены в Strict Mode. Если вы используете их в вашем кода, то Strict Mode выбросит исключение.
Объявление существующего имени объекта
Когда вы создаете объект с двумя одинаковыми ключами, то Strict Mode выбросит исключение TypeError.
Тесты
Вот исходник моих Strict Mode тестов. Каждый набор тестов снабжен комментарием, ссылающемся на часть спецификации ECMAScript, которую он тестирует. Эта версия может быть выполнена в «режиме консоли». Т.е. вы можете скопировать тест, вставить в консоль и выполнить без изменений. Этот же код, работающий в режиме «HTML» я использовал для создания тестовой страницы, которую я представил вам в начале статьи. Этот исходник с дополнительными объектами в моем github репозитории. Я уверен, что там есть пара ошибок — не стесняйтесь присылать ошибки!
От переводчика: тут в статье шел огромный кусок кода, закинул его на pastebin
Заключение
Запрещение обращение к некоторым возможностям языка для улучшения кода — вопрос спорный, давайте отложим эти споры. В защиту Strict Mode я хочу сказать, что это отличный компромисс между тотальными переменами (которые сломают обратную совместимость) и ничего не деланием (которое приведет к захламлению языка и научит разработчиков плохому).
Что ещё почитать
ECMA-262 5th Edition: The Strict Mode of ECMAScript
Asen Bozhilov: Strict tester
Таблица совместимости с ECMAScript 5, часть посвященная Strict mode. Это отличный источник, часть большой таблицы совместимости, разработанной Юрием Зайцевым (Juriy Zaytsev aka «kangax»)
От переводчика. Strict Mode поддерживают практически половина всех браузеров, кроме своих прекрасных ограничений и иммунитету к распространенным ошибкам Strict Mode дает и другие преимущества (статья mraleph). Скоро неиспользование Strict Mode станет плохим тоном (аналогично requestAnimationFrame vs setTimeout). Сейчас самое время начать эксперименты!
Зачем нужен Strict Mode в JavaScript?
Dec 22, 2019 · 6 min read
Строгий режим — это важная часть современного JavaScript. Он позволяет использовать ограниченный синтаксис JavaScript.
Семантика строгого режима отличается от старого “неаккуратного режима” JavaScript с его слабым синтаксисом и “замалчиваемыми” ошибками в коде — такие ошибки игнорируются, и код может запускаться с неожиданными результатами.
Строгий режим вносит несколько изменений в семантику JavaScript. Он заменяет исключениями “замалчиваемые” в обычном режиме ошибки, поэтому с этими ошибками код не запускается.
Он также исправляет ошибки, мешающие движкам JavaScript производить оптимизацию, и запрещает функции, которые могут быть определены в будущих версиях JavaScript.
Строгий режим п рименим как к отдельным функциям, так и к целому скрипту. Его нельзя применять только к операторам и другим блокам, заключенным в фигурные скобки. Чтобы скрипт использовал строгий режим, добавляем оператор «use strict» или ‘use strict’ в начало скрипта перед всеми остальными операторами.
Будьте внимательны: при объединении со скриптами, использующими строгий режим, скрипты, которые его не используют, начинают его использовать, и наоборот, поэтому объединять скрипты с разными режимами не стоит.
Чтобы применить строгий режим к функциям, нужно добавить оператор «use strict» или ‘use strict’ внутрь функции перед всеми остальными операторами. Он применяется ко всему, что находится внутри, включая вложенные функции.
В модулях JavaScript, представленных в ES2015, строгий режим применяется автоматически, поэтому его не нужно включать операторами.
Изменения в строгом режиме
Строгий режим изменяет и синтаксис, и поведение кода во время выполнения. Наиболее важные изменения:
Преобразование допустимых ошибок в недопустимые
В нестрогом режиме на некоторые допустимые ошибки JS никак не реагировал. Строгий режим ограничивает использование ошибочного синтаксиса и не позволяет коду запускаться с ошибками.
Код не запустится в строгом режиме — глобальную переменную badVariable можно создать только при выключенном строгом режиме, который нужен для предотвращения случайного создания глобальных переменных.
Теперь любой код с этой ранее допустимой ошибкой выдаст исключение. Это распространяется и на некорректный синтаксис, который игнорировался ранее.
Ниже несколько примеров неудачного синтаксиса:
В строгом режиме восьмеричная запись чисел также не разрешена. Она не является частью спецификации, но поддерживается в браузерах добавлением 0 к восьмеричным числам. Это сбивает разработчиков с толку, так как некоторые думают, что 0 перед числом ничего не значит. Как следствие, строгий режим не разрешает этот синтаксис и выдает ошибку.
Строгий режим предотвращает использование синтаксиса, усложняющего оптимизацию. Ему нужно знать, что переменная действительно хранится в том месте, где он думает, до того, как производить оптимизацию.
Строгий режим также запрещает удаление простых имен переменных, поэтому код ниже выдаст синтаксическую ошибку:
Запрет неверного синтаксиса
Неверный синтаксис метода eval и объекта argument не разрешен в строгом режиме.
Например, им нельзя задать новые значения или использовать их как имена переменных, функций или параметров функций.
Вот пример неверного использования eval и argument :
Строгий режим не разрешает создавать псевдоним для объекта arguments и задавать с ним новые значения.
Например, если у нас есть:
Оптимизация производительности
Например, если мы запустим код ниже:
Исправления безопасности
Это создает потенциальную дыру в безопасности, которая устраняется запретом доступа к этим двум свойствам функции.
Строгий режим был стандартом несколько лет. Обычно браузеры его поддерживают. Проблемы могут возникнуть только в старых браузерах, таких как Internet Explorer.
У других браузеров не должно быть проблем в работе со строгим режимом, поэтому его стоит использовать для предотвращения перечисленных выше ошибок.
Что значит «use strict»?
3 ответа 3
Строгий режим был введён в ECMAScript 5, и старые браузеры (IE9 и младше) его не поддерживают. То есть, не обращают внимания на установку по умолчанию и всё обрабатывается в неограниченном режиме.
Чтобы включить строгий режим в целом скрипте, надо поставить установку «use strict»; или ‘use strict’; в начало скрипта.
Чтобы включить строгий режим в функции, надо поставить установку в начало кода функции.
В чём различие между строгим режимом и неограниченным режимом?
нельзя присваивать значение в неопределённую переменную (спецификация §11.13.1). В неограниченном режиме создается глобальная переменная.
Также нельзя присваивать значение в свойство данных только для чтения.
нельзя использовать инструкцию with (спецификация §12.10).
в ES5 нельзя определить повторные свойства в литерале объекта (спецификация §11.1.5).
нельзя определить повторные формальные параметры функции (спецификация §13.1, §15.3.2).
изменения объекта arguments не изменяют аргументы (спецификация §10.6).
eval не может инстанциировать переменные и функции в контексте вызова (спецификация §10.4.2).
нельзя использовать argument.caller и arguments.callee (спецификация §13.2).
больше слов, зарезервированных для использования в будущем (спецификация §7.6.1.2).
нельзя использовать литералы восьмеричной СС (спецификация B.1.1, B.1.2).
Зачем в JavaScript нужен строгий режим?
Строгий режим (strict mode) — это важная часть современного JavaScript. Именно этот режим позволяет разработчикам пользоваться более ограниченным, чем стандартный, синтаксисом.
Семантика строгого режима отличается от традиционного нестрогого режима, который иногда называют «грязным» (sloppy mode). В таком режиме синтаксические правила языка не так строги, а когда происходят некоторые ошибки, система никак не оповещает о них пользователя. То есть — ошибки могут быть проигнорированы, а код, в котором они допущены, сможет выполняться дальше. Это способно привести к неожиданным результатам выполнения кода.
Строгий режим вносит в семантику JavaScript некоторые изменения. Он не даёт системе закрывать глаза на ошибки, выдавая соответствующие исключения. Это приводит к остановке выполнения программ.
Строгий режим, кроме того, помогает в написании программ, в которых нет недочётов, мешающих JS-движкам оптимизировать код. Далее, в этом режиме запрещено использование элементов синтаксиса, которые могут получить особый смысл в будущих версиях языка.
Особенности применения строгого режима
Если в проекте имеются некоторые скрипты, в которых не используется строгий режим, и другие, в которых этот режим используется, тогда может случиться так, что эти скрипты окажутся объединены.
Это приведёт к тому, что код, который не предназначен для выполнения в строгом режиме, окажется в таком состоянии, когда система попытается выполнить его в строгом режиме. Возможно и обратное — код, написанный для строгого режима, попадёт в нестрогий режим. Поэтому лучше всего не смешивать «строгие» и «нестрогие» скрипты.
Как уже было сказано, строгий режим можно применять к отдельным функциям. Для того чтобы это сделать — конструкцию «use strict» или ‘use strict’ надо поместить в верхнюю часть тела функции, до любых других команд. Строгий режим при таком подходе применяется ко всему, что размещено в теле функции, включая вложенные функции.
В JavaScript-модулях, которые появились в стандарте ES2015, строгий режим включён по умолчанию. Поэтому при работе с ними включать его явным образом не нужно.
Изменения, вводимые в работу JS-кода строгим режимом
▍Преобразование «тихих» ошибок в исключения
«Тихие» ошибки преобразуются в строгом режиме в исключения. В нестрогом режиме на такие ошибки система явным образом не реагирует. В строгом же режиме наличие таких ошибок приводит к неработоспособности кода.
Попытка выполнения любого кода, который, в обычном режиме, просто не работает, теперь приводит к выдаче исключения. В виде ошибок рассматриваются любые неправильные синтаксические конструкции, которые в нестрогом режиме просто игнорировались.
В строгом режиме исключение, например, будет выдано в следующих случаях:
К выдаче TypeError приведёт и попытка удаления неудаляемого свойства:
Строгий режим запрещает назначать объекту свойства с одинаковыми именами. Как результат — попытка выполнения следующего кода приведёт к возникновению синтаксической ошибки:
В строгом режиме запрещены параметры функций с одинаковыми именами. В результате попытка выполнения следующего кода приведёт к возникновению синтаксической ошибки:
В строгом режиме нельзя использовать восьмеричную запись чисел, предваряя число нулём. Этого нет в спецификации, но данная возможность поддерживается браузерами.
Такое положение дел путает разработчиков, заставляя их полагать, что 0, предшествующий числу, просто игнорируется, не имея особого смысла. В строгом режиме попытка воспользоваться числом, в начале которого стоит 0, приведёт к синтаксической ошибке.
Строгий режим, кроме того, запрещает использование конструкций, затрудняющих оптимизацию. Интерпретатору, перед выполнением оптимизации кода, нужно знать о том, что переменная хранится именно там, где, как считает интерпретатор, она хранится. В строгом режиме запрещается то, что мешает оптимизациям.
Предположим, есть такой код:
Результатом этой попытки будет синтаксическая ошибка.
Строгий режим, кроме того, запрещает удаление обычных переменных. В результате попытка выполнить следующий код приведёт к синтаксической ошибке:
▍Запрет некорректных синтаксических конструкций
Вот примеры некорректного использования eval и arguments :
В строгом режиме нельзя создавать псевдонимы для объекта arguments и устанавливать новые значения arguments через эти псевдонимы.
Предположим, имеется следующий код:
▍Оптимизации производительности
▍Изменения, имеющие отношение к безопасности
Эти возможности представляют собой потенциальную угрозу безопасности. В результате в строгом режиме доступ к этим свойствам запрещён.
В ES2015 и в более поздних версиях стандарта эти идентификаторы стали зарезервированными словами. И их нельзя использовать для именования переменных или свойств в строгом режиме.
Итоги
Строгий режим — это стандарт, который существует уже многие годы. Он пользуется чрезвычайно широкой поддержкой браузеров. Проблемы с кодом, выполняемом в строгом режиме, могут возникать лишь у старых браузеров, таких, как Internet Explorer.
У современных браузеров не должно возникать сложностей со строгим режимом JavaScript. В результате можно сказать, что этот режим стоит использовать ради предотвращения «тихих» ошибок и ради повышения безопасности приложений. «Тихие» ошибки преобразуются в исключения, препятствующие выполнению программ, а в плане повышения безопасности можно, например, отметить механизмы строгого режима, ограничивающие eval и предотвращающие доступ к стеку вызовов функций. Кроме того, использование строгого режима облегчает оптимизацию кода JS-движками и заставляет программиста осторожно обращаться с зарезервированными словами, которые могут найти применение в будущих версиях JavaScript.
Уважаемые читатели! Пользуетесь ли вы строгим режимом при написании JS-кода своих проектов?
Строгий режим Javascript
Директива «use strict»; указывает, что код JavaScript должен выполняться в «строгом режиме».
Директива «use strict» была добавлена в JavaScript 1.8.5 (ECMAScript версии 5).
Это не оператор, а константное выражение, которое игнорируется более ранними версиями JavaScript.
Цель директивы «use strict» — указать, что код должен выполняться в, так называемом, «строгом режиме».
В строгом режиме вы не можете, например, использовать не декларированные переменные.
Строгий режим поддерживается в:
Декларирование строгого режима
Строгий режим декларируется путем добавления директивы «use strict»; в начало скрипта или функции.
Если директива указана в начале скрипта, то она имеет глобальный эффект (весь код скрипта выполняется в строгом режиме):
Если директива указана внутри функции, то она имеет локальный эффект (только код внутри функции выполняется в строгом режиме):
Синтаксис директивы «use strict»;
Синтаксис директивы, декларирующей строгий режим, разработан таким образом, чтобы была совместимость со старыми версиями JavaScript.
Компилирование числовых (4 + 5;) или строковых («John Doe»;) констант в программе JavaScript не имеет побочных эффектов. Они просто компилируются в несуществующую переменную и умирают.
Таким образом, строковая константа «use strict»; срабатывает только в новых компиляторах, которые «понимают» ее значение.
Зачем нужен строгий режим?
Благодаря строгому режиму проще писать «безопасный» JavaScript код.
В строгом режиме ранее вполне приемлемый «плохой синтаксис» превращается в реальные ошибки.
К примеру, в обычном режиме JavaScript опечатка в имени переменной приводит к созданию новой глобальной переменной. В строгом режиме это приведет к ошибке, что защищает от случайного создания глобальных переменных.
В обычном режиме JavaScript разработчик не получит никакого сообщения об ошибке, если попытается присвоить какое-либо значение свойствам, не предназначенным для записи.
В строгом режиме любая попытка присвоить какое-либо значение не предназначенному для записи свойству, свойству, определенному, как только для чтения, несуществующей переменной или несуществующему объекту приведет к возникновению ошибки.
Ограничения в строгом режиме
Нельзя использовать переменные без декларирования:
Внимание! Объекты тоже переменные.
Нельзя использовать объекты без декларирования:
Нельзя удалять переменную (или объект):
Нельзя удалять функцию:
Одинаковые имена параметров запрещены:
Восьмеричные числовые константы запрещены:
Восьмеричные экранированные символы запрещены:
Запись в свойства, предназначенные только для чтения, запрещено:
Запись в свойства, предназначенные только для возврата значения, запрещено:
Нельзя удалять неудаляемые свойства:
Нельзя использовать строку «eval» в качестве имени переменной:
Нельзя использовать строку «arguments» в качестве имени переменной:
Нельзя использовать выражение with:
По соображениям безопасности, функции eval() запрещено создавать переменные в области видимости, где она была вызвана:
В вызовах функций как f(), значением this был глобальный объект. В строгом режиме оно undefined.
Задел на будущее
В строгом режиме нельзя использовать будущие зарезервированные слова. Это implements, interface, let, package, private, protected, public, static, yield.
ВНИМАНИЕ!
Директива «use strict» распознается только в начале скрипта или функции.


