Use strict javascript что это
Перейти к содержимому

Use strict javascript что это

  • автор:

use strict

‘use strict’ включает строгий режим выполнения JavaScript. Эта строка должна располагаться в самом начале скрипта, иначе строгий режим не будет работать. В строгом режиме интерпретатор будет явно выбрасывать ошибки на действия, которые ранее пропускал. Если строгий режим был включён, то отключить его для файла уже нельзя.

Пример

Скопировать ссылку «Пример» Скопировано

 'use strict' // Располагаем строку в самом начале файла! const name = 'Alex'// . другой код 'use strict' // Располагаем строку в самом начале файла! const name = 'Alex' // . другой код      

Как понять

Скопировать ссылку «Как понять» Скопировано

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

Строгий режим делает следующее:

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

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

Нельзя использовать переменные без объявления

Скопировать ссылку «Нельзя использовать переменные без объявления» Скопировано

Интерпретатор в строгом режиме выбросит ошибку, если обратиться к переменной без её объявления:

 'use strict' const name = 'Anna'console.log(name)// Anna age = 24console.log(age)// Uncaught ReferenceError: age is not defined 'use strict' const name = 'Anna' console.log(name) // Anna age = 24 console.log(age) // Uncaught ReferenceError: age is not defined      

Без строгого режима интерпретатор в таком случае создаст переменную age в глобальной области видимости. Если выполнять код из примера в консоли браузера без ‘use strict’ , то все выполнится без ошибок, а в глобальный объект window запишется поле age со значением 24 .

Явная ошибка если значение поля нельзя изменить или удалить

Скопировать ссылку «Явная ошибка если значение поля нельзя изменить или удалить» Скопировано

С помощью методов Object . define Property ( ) или Object . prevent Extensions ( ) в JavaScript можно запретить перезаписывать поля объекта. При включённом строгом режиме попытка перезаписать поле приведёт к ошибке.

 'use strict' const obj = <> Object.defineProperty(obj, 'someProp', < value: 'Alex', writable:false >) console.log(obj.someProp)// Alex obj.someProp = 'James'// Uncaught TypeError: Cannot assign to read only property 'someProp' of object # 'use strict' const obj = > Object.defineProperty(obj, 'someProp',  value: 'Alex', writable:false >) console.log(obj.someProp) // Alex obj.someProp = 'James' // Uncaught TypeError: Cannot assign to read only property 'someProp' of object #     
 'use strict' const notExtensableObj = <> Object.preventExtensions(notExtensableObj) notExtensableObj.someProp = 'Value'// Uncaught TypeError: Can't add property someProp, object is not extensible 'use strict' const notExtensableObj = > Object.preventExtensions(notExtensableObj) notExtensableObj.someProp = 'Value' // Uncaught TypeError: Can't add property someProp, object is not extensible      

Ошибка будет выброшена в строгом режиме и при попытке удаления поля из объекта, когда это сделать нельзя.

 const obj = <> Object.defineProperty(obj, 'someProp',  value: 'Anna', configurable: false>) delete obj.someProp// Uncaught TypeError: Cannot delete property 'someProp' of # const obj = > Object.defineProperty(obj, 'someProp',  value: 'Anna', configurable: false >) delete obj.someProp // Uncaught TypeError: Cannot delete property 'someProp' of #     

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

Параметры функции не могут иметь одинаковые имена

Скопировать ссылку «Параметры функции не могут иметь одинаковые имена» Скопировано

Если в функции объявить два параметра с одинаковым именем, то строгий режим выбросит ошибку выполнения.

 'use strict' // Uncaught SyntaxError: Duplicate parameter name not allowed in this contextfunction sum(a, b, a)  // . > 'use strict' // Uncaught SyntaxError: Duplicate parameter name not allowed in this context function sum(a, b, a)  // . >      

Без use strict интерпретатор выполнит код без ошибок, но обратиться к переопределённому параметру будет невозможно.

 function sum(a, b, a)  console.log(a) console.log(b)> sum(1, 2, 3) // Выведет 3 и 2, первый аргумент потерян навсегда function sum(a, b, a)  console.log(a) console.log(b) > sum(1, 2, 3) // Выведет 3 и 2, первый аргумент потерян навсегда      

Другое поведение this

Скопировать ссылку «Другое поведение this» Скопировано

При включённом строгом режиме this больше не будет по умолчанию ссылаться на глобальный объект.

 'use strict' function logThis()  console.log(this)> logThis()// Выведет undefined 'use strict' function logThis()  console.log(this) > logThis() // Выведет undefined      

Без use strict если вызывать функцию в глобальном контексте (например в консоли браузера), то this всегда будет ссылаться на глобальный объект.

Запрещено использовать зарезервированные слова

Скопировать ссылку «Запрещено использовать зарезервированные слова» Скопировано

В строгом в режиме запрещено использовать в коде некоторые слова, которые были специально зарезервированы для того, чтобы использовать их в будущем. Это слова implements , interface , let , package , private , protected , public , static , yield . Некоторые из этих слов уже используется в данный момент: например объявление переменных через let или возвращение значения из генератора с помощью yield .

Ограничение небезопасных конструкций

Скопировать ссылку «Ограничение небезопасных конструкций» Скопировано

Дополнительно включение строгого режима не позволяет использовать в коде конструкцию with и очищает переменные, созданные с помощью eval ( ) . Обе эти конструкции устарели и являются потенциально опасными, потому не используются в современном JavaScript.

Как пишется

Скопировать ссылку «Как пишется» Скопировано

Все современные сборщики JavaScript умеют самостоятельно добавлять ‘use strict’ в файлы. Потому в данный момент обычно никто в коде явно не объявляет строгий режим. А с появлением в JavaScript модулей все они по умолчанию работают в строгом режиме.

‘use strict’ называется директивой, так как это не просто строка, а специальная инструкция для интерпретатора. Потому очень важно поместить объявление строгого режима в самом начале скрипта, чтобы это была самая первая строчка, которая исполнится.

 'use strict' // Включили строгий режим // Далее остальной код 'use strict' // Включили строгий режим // Далее остальной код      

Если поместить строку ниже, то включение строгого режима не произойдёт.

 console.log(1 + 2)// 3 'use strict' // Просто объявление строки, строгий режим не включился // Код ниже работает без строгого режима console.log(1 + 2) // 3 'use strict' // Просто объявление строки, строгий режим не включился // Код ниже работает без строгого режима      

Над ‘use strict’ можно размещать только комментарии.

Strict mode

Режим strict (строгий режим), введённый в ECMAScript 5, позволяет использовать более строгий вариант JavaScript. Это не просто подмножество языка: в нем сознательно используется семантика, отличающаяся от обычно принятой. Не поддерживающие строгий режим браузеры будут по-другому выполнять код, написанный для строгого режима, поэтому не полагайтесь на строгий режим без тестирования поддержки используемых особенностей этого режима. Строгий и обычный режим могут сосуществовать одновременно, а скрипт может переключаться в строгий режим по мере надобности.

Строгий режим принёс ряд изменений в обычную семантику JavaScript. Во-первых, строгий режим заменяет исключениями некоторые ошибки, которые интерпретатор JavaScript ранее молча пропускал. Во-вторых, строгий режим исправляет ошибки, которые мешали движкам JavaScript выполнять оптимизацию — в некоторых случаях код в строгом режиме может быть оптимизирован для более быстрого выполнения, чем код в обычном режиме. В-третьих, строгий режим запрещает использовать некоторые элементы синтаксиса, которые, вероятно, в следующих версиях ECMAScript получат особый смысл.

Если вы хотите изменить свой код так, чтобы он работал в строгой версии JavaScript, посмотрите статью Переход к строгому режиму .

Активизация строгого режима

Строгий режим применяется ко всему скрипту или к отдельным функциям. Он не может быть применён к блокам операторов, заключённых в фигурные скобки — попытка использовать его в подобном контексте будет проигнорирована. Код в eval , Function , в атрибутах обработчиков событий, в строках, переданных в setTimeout , и т.п. рассматривается как законченный скрипт, и активизация строгого режима в нём выполняется ожидаемым образом.

Строгий режим для скриптов

Чтобы активизировать строгий режим для всего скрипта, нужно поместить оператор «use strict»; или ‘use strict’; перед всеми остальными операторами скрипта (выдержать приведённый синтаксис буквально).

// Синтаксис переключения в строгий режим всего скрипта "use strict"; var v = "Привет! Я скрипт в строгом режиме!"; 

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

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

Строгий режим для функций

Аналогично, чтобы включить строгий режим для функции, поместите оператор «use strict»; (или ‘use strict’; ) в тело функции перед любыми другими операторами.

function strict()  // Строгий режим на уровне функции "use strict"; function nested()  return "И я тоже!"; > return "Привет! Я функция в строгом режиме! " + nested(); > function notStrict()  return "Я не strict."; > 

Строгий режим для модулей

ECMAScript 2015 представил модули JavaScript и, следовательно, 3-й способ войти в строгий режим. Все содержимое модулей JavaScript автоматически находится в строгом режиме, и для его запуска не требуется никаких инструкций.

function strict() < // Потому что это модуль, я strict по умолчанию >export default strict;

Изменения в строгом режиме

Строгий режим изменяет синтаксис и поведение среды исполнения. Изменения главным образом попадают в следующие категории: преобразование ошибок в исключения; изменения, упрощающие вычисление переменной в определённых случаях использования её имени; изменения, упрощающие eval и arguments ; изменения, упрощающие написание «безопасного» JavaScript, и изменения, предвосхищающие дальнейшее развитие ECMAScript.

Преобразование ошибок в исключения

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

Во-первых, строгий режим делает невозможным случайное создание глобальных переменных. В обычном JavaScript опечатка в имени переменной во время присваивания приводит к созданию нового свойства глобального объекта, и выполнение продолжается (хотя в современном JavaScript оно, вероятно, аварийно завершится в дальнейшем). Присваивания, которые могут случайно создать глобальную переменную, в строгом режиме выбрасывают исключение:

"use strict"; // Предполагая, что не существует глобальной переменной mistypeVaraible = 17; // mistypedVaraible, эта строка выбросит ReferenceError // из-за опечатки в имени переменной 

Во-вторых, строгий режим заставляет присваивания, которые всё равно завершились бы неудачей, выбрасывать исключения. Например, NaN — глобальная переменная, защищённая от записи. В обычном режиме присваивание NaN значения ничего не делает; разработчик не получает никакого сообщения об ошибке. В строгом режиме присваивание NaN значения выбрасывает исключение. Любое присваивание, которое в обычном режиме завершается неудачей (присваивание значения свойству, защищённому от записи; присваивание значения свойству, доступному только на чтение; присваивание нового свойства нерасширяемому объекту), в строгом режиме выбросит исключение:

"use strict"; // Присваивание значения глобальной переменной, защищённой от записи var undefined = 5; // выдаст TypeError var Infinity = 5; // выдаст TypeError // Присваивание значения свойству, защищённому от записи var obj1 = >; Object.defineProperty(obj1, "x",  value: 42, writable: false >); obj1.x = 9; // выдаст TypeError // Присваивание значения свойству, доступному только для чтения var obj2 =  get x()  return 17; >, >; obj2.x = 5; // выдаст TypeError // Задание нового свойства нерасширяемому объекту var fixed = >; Object.preventExtensions(fixed); fixed.newProp = "ohai"; // выдаст TypeError 

В-третьих, в строгом режиме попытки удалить неудаляемые свойства будут вызывать исключения (в то время как прежде такая попытка просто не имела бы эффекта):

"use strict"; delete Object.prototype; // выдаст TypeError 

В-четвёртых, строгий режим требует, чтобы все свойства, перечисленные в сериализованном объекте, встречались только один раз. В обычном коде имена свойств могут дублироваться, а значение свойства определяется последним объявлением. Но, в таком случае, дублирование — просто почва для багов, если код редактируется с тем, чтобы поменять значение свойства как-то по-другому, кроме изменения последнего объявления. Дублирование имён свойств в строгом режиме является синтаксической ошибкой:

Примечание: Это уже не является проблемой в ECMAScript 2015 (баг 1041128).

"use strict"; var o =  p: 1, p: 2 >; // . синтаксическая ошибка 

В-пятых, строгий режим требует, чтобы имена аргументов в объявлении функций встречались только один раз. В обычном коде последний повторённый аргумент скрывает предыдущие аргументы с таким же именем. Эти предыдущие аргументы всё ещё доступны через arguments[i] , так что они не полностью потеряны. Тем не менее, такое сокрытие несёт в себе мало смысла и, скорее всего, не имеет под собой цели (например, может скрывать опечатку), поэтому в строгом режиме дублирование имён аргументов является синтаксической ошибкой:

function sum(a, a, c)  // . синтаксическая ошибка "use strict"; return a + a + c; // ошибка, если код был запущен > 

В-шестых, строгий режим запрещает синтаксис восьмеричной системы счисления. Восьмеричный синтаксис не является частью ECMAScript, но поддерживается во всех браузерах с помощью дописывания нуля спереди к восьмеричному числу: 0644 === 420 и «\045» === «%» . В ECMAScript 2015 восьмеричное число поддерживается также с помощью дописывания перед числом » 0o «. Т.е.

var a = 0o10; // ES2015: Восмеричное

Иногда начинающие разработчики думают, что ведущий ноль не имеет семантического значения, и используют его для выравнивания — но это меняет значение числа! Восьмеричный синтаксис редко бывает полезен и может быть неправильно использован, поэтому строгий режим считает восьмеричные числа синтаксической ошибкой:

"use strict"; var sum = 015 + // . синтаксическая ошибка 197 + 142; var sumWithOctal = 0o10 + 8; console.log(sumWithOctal); // 16 

В-седьмых, строгий режим в ECMAScript 2015 запрещает установку свойств primitive значениям. Без строгого режима, установка свойств просто игнорируется (no-op), со строгим режимом, однако, выдаёт TypeError .

(function() < 'use strict'; false.true = ''; // TypeError (14).sailing = 'home'; // TypeError 'with'.you = 'far away'; // TypeError >)();

Упрощение работы с переменными

Строгий режим упрощает сопоставление имени переменной с местом её определения в коде. Многие оптимизации времени компиляции полагаются на возможность считать, что переменная X хранится в этом конкретном месте исходного кода. Иногда, при компиляции JavaScript простое сопоставление имени переменной с местом её определения в коде не возможно, без выполнения того самого кода. Строгий же режим исключает большинство таких случаев, благодаря чему оптимизации компилятора работают эффективнее.

Во-первых, строгий режим запрещает использование with . Проблема с with в том, что во время выполнения любое имя внутри блока может ссылаться как на свойство обрабатываемого объекта, так и на переменную в окружающем (или даже в глобальном) контексте — невозможно знать об этом заранее. Строгий режим считает with синтаксической ошибкой, поэтому не остаётся шанса использовать имя переменной внутри with для ссылки на неизвестное место во время выполнения:

"use strict"; var x = 17; with (obj)  // . синтаксическая ошибка // Если код не в строгом режиме, то будет ли x ссылаться на переменную var x, или // на свойство obj.x? Предугадать без запуска кода невозможно, // следовательно такой код не может быть эффективно оптимизирован. x; > 

Простая альтернатива with уже существует — присваивание объекта переменной с коротким именем и затем доступ к нужному свойству как свойству этой переменной.

Во-вторых, eval в строгом режиме не добавляет новых переменных в окружающий контекст. В обычном режиме, при вызове eval(«var x;») переменная x добавится в область видимости окружающей функции либо в глобальный контекст. В общем случае, это означает, что в каждой функции, в которой присутствует вызов eval , имена переменных которые не ссылаются на аргумент или локальную переменную, должны сопоставляться с местом их определения в коде только во время выполнения (потому что eval мог ввести новую переменную, которая может перекрыть внешнюю переменную). В строгом режиме eval создаёт переменные только в контексте выполняемого кода, так что eval не может повлиять на то, ссылается ли имя на локальную или на внешнюю переменную:

var x = 17; var evalX = eval("'use strict'; var x = 42; x"); console.assert(x === 17); console.assert(evalX === 42); 

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

function strict1(str)  "use strict"; return eval(str); // str будет выполнен как код строгого режима > function strict2(f, str)  "use strict"; return f(str); // не eval(. ): str выполнится в строгом режиме только в том // случае, если в нем содержится вызов строгого режима > function nonstrict(str)  return eval(str); // str выполнится в строгом режиме только в том // случае, если в нем содержится вызов строгого режима > strict1("'Строгий режим!'"); strict1("'use strict'; 'Строгий режим!'"); strict2(eval, "'Не строгий режим.'"); strict2(eval, "'use strict'; 'Строгий режим!'"); nonstrict("'Не строгий режим.'"); nonstrict("'use strict'; 'Строгий режим!'"); 

Таким образом, имена в строгом коде, передаваемом в eval , ведут себя так же, как имена в нестрогом коде, передаваемом в eval внутри строгого режима.

В-третьих, строгий режим запрещает удаление простых имён. delete name в строгом режиме является синтаксической ошибкой:

"use strict"; var x; delete x; // . синтаксическая ошибка eval("var y; delete y;"); // . синтаксическая ошибка 

Упрощение eval и arguments

В строгом режиме снижается количество странностей в поведении arguments и eval , оба из которых примешивают определённое количество магии в обычный код. Так eval добавляет или удаляет переменные и меняет их значения, а переменная arguments может удивить своими проиндексированными свойствами, которые являются ссылками (синонимами) для поименованных аргументов функции. Строгий режим делает большой шаг в прояснении этих двух ключевых слов, но полное их обуздание произойдёт лишь в следующей редакции ECMAScript.

Во-первых, ключевые слова eval и arguments не могут быть переопределены или изменены. Все подобные попытки это сделать являются синтаксическими ошибками:

"use strict"; eval = 17; arguments++; ++eval; var obj =  set p(arguments) > >; var eval; try  > catch (arguments) > function x(eval) > function arguments() > var y = function eval() >; var f = new Function("arguments", "'use strict'; return 17;"); 

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

function f(a)  "use strict"; a = 42; return [a, arguments[0]]; > var pair = f(17); console.assert(pair[0] === 42); console.assert(pair[1] === 17); 

В-третьих, свойство arguments.callee больше не поддерживается. В обычном коде свойство arguments.callee ссылается на саму функцию для вызова которой и был создан объект arguments . Малоприменимое свойство, так как функция заранее известна, и к ней можно обратиться и по её имени непосредственно. Более того, arguments.callee значительно затрудняет такую оптимизацию, как инлайнинг, потому как должна быть сохранена возможность обратиться к незаинлайненой функции на случай, если присутствует обращение к arguments.callee. В строгом режиме arguments.callee превращается в неудаляемое свойство, которое выбрасывает предостерегающее исключение при любой попытке обращения к нему:

"use strict"; var f = function ()  return arguments.callee; >; f(); // выдаст TypeError 

«Безопасный» JavaScript

Строгий режим упрощает написание «безопасного» JavaScript-кода. Сейчас некоторые веб-сайты предоставляют пользователям возможность писать JavaScript, который будет выполняться на сайте от имени других пользователей. В браузерах, JavaScript может иметь доступ к приватной информации пользователя, поэтому, в целях ограничения доступа к запретной функциональности, такой JavaScript перед выполнением должен быть частично преобразован. Гибкость JavaScript делает это практически невозможным без многочисленных проверок во время исполнения. Функционал, исполняемый языком иногда столь массивен, что выполнение любых дополнительных проверок во время исполнения скрипта приведёт к значительной потере производительности. Однако, некоторые особенности строгого режима, плюс обязательное требование того, чтобы JavaScript, загруженный пользователем, имел строгий режим и вызывался определённым способом, существенно снижают потребность в таких проверках.

Во-первых, значение, передаваемое в функцию как this , в строгом режиме не приводится к объекту (не «упаковывается»). В обычной функции this всегда представляет собой объект: либо это непосредственно объект, в случае вызова с this , представляющим объект-значение; либо значение, упакованное в объект, в случае вызова с this типа Boolean, string, или number; либо глобальный объект, если тип this это undefined или null . (Для точного определения конкретного this используйте call , apply , или bind .) Автоматическая упаковка не только снижает производительность, но и выставляет на показ глобальный объект, что в браузерах является угрозой безопасности, потому что глобальный объект предоставляет доступ к функциональности, которая должна быть ограничена в среде «безопасного» JavaScript. Таким образом, для функции в строгом режиме точно определённый this не упаковывается в объект, а если не определён точно, this является undefined :

"use strict"; function fun()  return this; > console.assert(fun() === undefined); console.assert(fun.call(2) === 2); console.assert(fun.apply(null) === null); console.assert(fun.call(undefined) === undefined); console.assert(fun.bind(true)() === true); 

Во-вторых, в строгом режиме больше не представляется возможным осуществлять «прогонку» стека JavaScript посредством базовых расширений ECMAScript. В обычном коде, использующем эти расширения, когда функция fun находится в процессе своего вызова, fun.caller представляет собой функцию, вызвавшую fun , а fun.arguments это аргументы для данного вызова fun . Оба расширения являются проблемными для «безопасного» JavaScript, так как они позволяют «безопасному» коду получить доступ к «привилегированным» функциям и их (потенциально небезопасным) аргументам. Если fun находится в строгом режиме, то fun.caller , так же как и fun.arguments, представляют собой неудаляемые свойства, которые приведут к вызову исключения при попытке их чтения или записи:

function restricted()  "use strict"; restricted.caller; // выдаст TypeError restricted.arguments; // выдаст TypeError > function privilegedInvoker()  return restricted(); > privilegedInvoker(); 

В-третьих, в функциях строгого режима свойство arguments больше не предоставляет доступ к переменным, созданным внутри функции. В некоторых предыдущих реализациях ECMAScript arguments.caller представлял собой объект, свойства которого являлись ссылками на переменные, созданные внутри функции при её вызове. Это представляет собой угрозу безопасности, так как нарушает возможность скрывать приватные данные внутри функций (замыканий). Также это делает невозможными большинство оптимизаций. Исходя из этих причин, ни один из современных браузеров не реализует этого поведения. Но всё же, ввиду своей исторической функциональности, arguments.caller для функций в строгом режиме всё ещё является неудаляемым свойством, которое вызывает исключение при попытке его чтения или записи:

"use strict"; function fun(a, b)  "use strict"; var v = 12; return arguments.caller; // выдаст TypeError > fun(1, 2); // не выводит v (или a, или b) 

Подготовка почвы для будущих версий ECMAScript

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

Во-первых, в строгом режиме зарезервирован для использования следующий список ключевых слов: implements , interface , let , package , private , protected , public , static и yield . В строгом режиме, следовательно, вы не можете задействовать эти слова для именования или обращения к переменным или аргументам.

function package(protected)  // . "use strict"; var implements; // . // . interface: while (true)  break interface; // . > function private() > // . > function fun(static)  "use strict"; > // . 

Два замечания, специфичных для Mozilla: Первое, если ваш код создан на JavaScript 1.7 или выше (например, chrome code, или тег , нельзя будет использовать let / yield в качестве идентификаторов. Второе, в то время как ES5 зарезервировал слова class , enum , export , extends , import и super для любого режима, в Firefox 5 Mozilla они были зарезервированы намного раньше и лишь для строгого режима.

Во-вторых, в строгом режиме запрещается объявление функций глубже самого верхнего уровня скрипта или функции. В обычном коде в браузерах, объявление функций позволено "везде", что не является частью ES5 (или даже ES3!) Это расширение различных браузеров, не имеющее общего совместимого подхода. Есть надежда, что в последующих редакциях ECMAScript будет определена новая семантика для объявления функций вне верхнего уровня скрипта или функции. Запрет на объявление таких функций в строгом режиме производит "зачистку" для спецификации в будущем релизе ECMAScript:

"use strict"; if (true)  function f() > // . синтаксическая ошибка f(); > for (var i = 0; i  5; i++)  function f2() > // . синтаксическая ошибка f2(); > function baz()  // верно function eit() > // тоже верно > 

Данный запрет не является особенностью строгого режима, потому что такое объявление функций является одним из расширений основного ES5. Но это рекомендация комитета ECMAScript, и браузеры реализуют её.

Строгий режим в браузерах

В большинстве браузеров в настоящее время строгий режим реализован. Однако не стоит впадать в слепую зависимость от него, потому что существует множество Версий браузеров, поддерживающих строгий режим лишь частично или вовсе не поддерживающих оный (например, Internet Explorer ниже версии 10!). Строгий режим изменяет семантику. Надежда на эти изменения приведёт к ошибкам и погрешностям в браузерах, в которых строгий режим не реализован. Проявляйте осторожность при использовании строгого режима, и подкрепляйте надёжность строгого режима тестами особенностей, которые проверяют, насколько верно реализованы его фрагменты. Наконец, старайтесь тестировать свой код в браузерах, как поддерживающих, так и не поддерживающих строгий режим. Если вы проводите тестирование только в тех браузерах, которые не поддерживают строгий режим, то вполне вероятно у вас появятся проблемы в браузерах, его поддерживающих, и наоборот.

Смотрите также

  • Where's Walden? » New ES5 strict mode support: now with poison pills!
  • Where's Walden? » New ES5 strict mode requirement: function statements not at top level of a program or function are prohibited
  • Where's Walden? » New ES5 strict mode support: new vars created by strict mode eval code are local to that code only
  • John Resig - ECMAScript 5 Strict Mode, JSON, and More
  • ECMA-262-5 in detail. Chapter 2. Strict Mode.
  • Strict mode compatibility table

Found a content problem with this page?

  • Edit the page on GitHub.
  • Report the content issue.
  • View the source on GitHub.

This page was last modified on 7 авг. 2023 г. by MDN contributors.

Как работает режим strict в JavaScript

Рассмотрели строгий режим strict на JavaScript, и обсудили, что это такое, как он работает и как он помогает писать лучший код.

JavaScript — универсальный и широко используемый язык программирования для веб-разработки. Однако его гибкость иногда может привести к непредвиденным последствиям, поэтому разработчикам крайне важно писать надежный и удобный для сопровождения код.

Один из способов добиться этого — использовать «строгий режим» JavaScript или режим Strict.

В этой статье мы подробно рассмотрим режим strict на JavaScript, обсудим, что это такое, как он работает и как он может помочь вам писать лучший код.

Что такое режим Strict

Строгий режим или Strict — это функция, представленная в ECMAScript 5 (ES5), которая позволяет разработчикам использовать более строгий и безопасный вариант JavaScript.

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

Зачем использовать строгий режим

  1. Предотвращение ошибок. Строгий режим помогает предотвратить потенциальные ошибки, которые в обычном режиме просто игнорировались бы.
  2. Упрощенная отладка. Благодаря раннему обнаружению ошибок строгий режим может ускорить и повысить эффективность отладки.
  3. Улучшенная производительность. Некоторые оптимизации возможны только в строгом режиме, поскольку он устраняет некоторые подверженные ошибкам функции языка.
  4. Забота о будущем. Строгий режим запрещает использование устаревших функций или функций, которые скоро станут устаревшими, помогая вашему коду оставаться совместимым с будущими версиями JavaScript.

Как включить строгий режим

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

"use strict"; 

Эта директива информирует интерпретатор JavaScript о необходимости применения правил Strict для всего файла или функции, в которой он появляется.

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

Использование строгого режима в Node

Node также поддерживает строгий режим. У вас есть 2 варианта с этим подходом.

Первый вариант — использовать "use strict"; в начале файлов, которые вы обрабатываете в Node.

Второй — загрузить узел через cli в строгом режиме:

node --use_strict 

Главное, что следует помнить — вы загружаете всё приложение в строгом режиме. Режим затронет любые сторонние библиотеки, которые вы используете.

Если сторонняя программа плохо работает в строгом режиме, вас оповестят об этом, и, возможно, вам не следует использовать Strict.

Ограничения Strict-режима

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

Объявление переменной

В строгом режиме вы должны объявить переменные с помощью ключевых слов var, let или const перед их использованием. В противном случае возникнет ошибка.

Это предотвратит случайное создание глобальной переменной.

// Non-strict mode undeclaredVariable = 42; // Creates a global variable // Strict mode "use strict"; undeclaredVariable = 42; // Throws a ReferenceError 

Повторяющиеся имена параметров

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

// Non-strict mode function duplicateParameters(a, a) < // No error >// Strict mode "use strict"; function duplicateParameters(a, a) < // Throws a SyntaxError > 

Восьмеричные литералы

Восьмеричные литералы (например, 0123) не допускаются в строгом режиме, и попытка их использования приведет к синтаксической ошибке. Вместо этого используйте префикс 0o для восьмеричных чисел.

// Non-strict mode var octal = 0123; // No error // Strict mode "use strict"; var octal = 0123; // Throws a SyntaxError var octal = 0o123; // Correct octal syntax in strict mode 

Назначение свойств только для чтения

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

// Non-strict mode undefined = 42; // No error // Strict mode "use strict"; undefined = 42; // Throws a TypeError 

Оператор with

Оператор with запрещен в строгом режиме, так как он может привести к неоднозначному и трудно отлаживаемому коду.

Использование with в строгом режиме приведет к синтаксической ошибке.

// Non-strict mode with (object) < // Do something with object's properties >// Strict mode "use strict"; with (object) < // Throws a SyntaxError > 

Изменения eval

В строгом режиме eval имеет собственную область видимости, и переменные, объявленные внутри вызова eval , не попадают в окружающую область.

Кроме того, присвоение eval или использование его в качестве имени функции запрещено.

// Non-strict mode eval("var localVar = 42;"); console.log(localVar); // Logs 42 // Strict mode "use strict"; eval("var localVar = 42;"); console.log(localVar); // Throws a ReferenceError 

Значение this

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

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

// Non-strict mode function logThis() < console.log(this); >logThis(); // Logs the global object (e.g., `window` in browsers) // Strict mode "use strict"; function logThis() < console.log(this); >logThis(); // Logs `undefined` 

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

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

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

Следите за новыми постами по любимым темам

Подпишитесь на интересующие вас теги, чтобы следить за новыми постами и быть в курсе событий.

Зачем в JavaScript нужен строгий режим?

Строгий режим (strict mode) — это важная часть современного JavaScript. Именно этот режим позволяет разработчикам пользоваться более ограниченным, чем стандартный, синтаксисом.

Семантика строгого режима отличается от традиционного нестрогого режима, который иногда называют «грязным» (sloppy mode). В таком режиме синтаксические правила языка не так строги, а когда происходят некоторые ошибки, система никак не оповещает о них пользователя. То есть — ошибки могут быть проигнорированы, а код, в котором они допущены, сможет выполняться дальше. Это способно привести к неожиданным результатам выполнения кода.

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

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

Особенности применения строгого режима

Строгий режим можно применять к отдельным функциям или к целому скрипту. Его нельзя применить только к отдельным инструкциям или к блокам кода, заключённым в фигурные скобки. Для того чтобы использовать строгий режим на уровне целого скрипта, в самое начало файла, до любых других команд, нужно поместить конструкцию "use strict" или 'use strict' .

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

Это приведёт к тому, что код, который не предназначен для выполнения в строгом режиме, окажется в таком состоянии, когда система попытается выполнить его в строгом режиме. Возможно и обратное — код, написанный для строгого режима, попадёт в нестрогий режим. Поэтому лучше всего не смешивать «строгие» и «нестрогие» скрипты.

Как уже было сказано, строгий режим можно применять к отдельным функциям. Для того чтобы это сделать — конструкцию "use strict" или 'use strict' надо поместить в верхнюю часть тела функции, до любых других команд. Строгий режим при таком подходе применяется ко всему, что размещено в теле функции, включая вложенные функции.

const strictFunction = ()=>< 'use strict'; const nestedFunction = ()=> < // эта функция тоже использует строгий режим >>

В JavaScript-модулях, которые появились в стандарте ES2015, строгий режим включён по умолчанию. Поэтому при работе с ними включать его явным образом не нужно.

Изменения, вводимые в работу JS-кода строгим режимом

Строгий режим влияет и на синтаксис кода, и на то, как код ведёт себя во время выполнения программы. Ошибки в коде преобразуются в исключения. То, что в нестрогом режиме тихо даёт сбой, в строгом вызывает сообщение об ошибке. Это похоже на то, как в нестрогом режиме система реагирует на синтаксические ошибки. В строгом режиме упрощается работа с переменными, жёстко регулируется использование функции eval и объекта arguments , упорядочивается работа с конструкциями, которые могут быть реализованы в будущих версиях языка.

▍Преобразование «тихих» ошибок в исключения

«Тихие» ошибки преобразуются в строгом режиме в исключения. В нестрогом режиме на такие ошибки система явным образом не реагирует. В строгом же режиме наличие таких ошибок приводит к неработоспособности кода.

Так, благодаря этому сложно совершить ошибку случайного объявления глобальной переменной, так как переменные и константы в строгом режиме нельзя объявлять без использования директив var , let или const . В результате создание переменных без этих директив приведёт к неработоспособности программы. Например, попытка выполнения следующего кода приведёт к выдаче исключения ReferenceError :

'use strict'; badVariable = 1;

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

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

Так, например, в строгом режиме нельзя выполнять операции присваивания значений таким сущностям, предназначенным только для чтения, как arguments , NaN или eval .

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

  • попытка присваивания значения свойству, предназначенному только для чтения, вроде некоего неперезаписываемого глобального свойства;
  • попытка записи значения в свойство, у которого есть лишь геттер;
  • попытка записи чего-либо в свойство нерасширяемого объекта.
'use strict'; let undefined = 5; let Infinity = 5; let obj = <>; Object.defineProperty(obj, 'foo', < value: 1, writable: false >); obj.foo = 1 let obj2 = < get foo() < return 17; >>; obj2.foo = 2 let fixedObj = <>; Object.preventExtensions(fixedObj); fixed.bar= 1;

Попытка выполнения подобных фрагментов кода в строгом режиме приведёт к выдаче исключения TypeError . Так, например, undefined и Infinity — это глобальные сущности, значения которых нельзя перезаписывать, а свойство foo объекта obj не поддерживает перезапись. Свойство foo объекта obj2 имеет лишь геттер. Объект fixedObj сделан нерасширяемым с помощью метода Object.preventExtensions .

К выдаче TypeError приведёт и попытка удаления неудаляемого свойства:

'use strict'; delete Array.prototype

Строгий режим запрещает назначать объекту свойства с одинаковыми именами. Как результат — попытка выполнения следующего кода приведёт к возникновению синтаксической ошибки:

'use strict'; let o = < a: 1, a: 2 >;

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

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

'use strict'; const multiply = (x, x, y) => x*x*y;

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

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

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

Один из примеров подобного запрета касается инструкции with . Если пользоваться данной инструкцией, то это мешает JS-интерпретатору узнать о том, к какой именно переменной или к какому именно свойству мы обращаемся, так как возможно такое, что сущность с одним и тем же именем имеется и снаружи, и внутри блока инструкции with .

Предположим, есть такой код:

let x = 1; with (obj)

Интерпретатор не сможет узнать о том, ссылается ли переменная x , находящаяся внутри блока with , на внешнюю переменную x , или на свойство obj.x объекта obj .

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

'use strict'; let x = 1; with (obj)

Результатом этой попытки будет синтаксическая ошибка.

Ещё в строгом режиме запрещено объявлять переменные в коде, переданном методу eval .

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

Для того чтобы это предотвратить, в строгом режиме запрещено объявлять переменные в коде, передаваемом в виде строки методу eval .

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

'use strict'; let x; delete x;

▍Запрет некорректных синтаксических конструкций

В строгом режиме запрещено неправильное использование eval и arguments . Речь идёт о запрете всяческих манипуляций с ними. Например — это нечто вроде присваивания им новых значений, использование их имён в роли имён переменных, функций, параметров функций.

Вот примеры некорректного использования eval и arguments :

'use strict'; eval = 1; arguments++; arguments--; ++eval; eval--; let obj = < set p(arguments) < >>; let eval; try < >catch (arguments) < >try < >catch (eval) < >function x(eval) < >function arguments() < >let y = function eval() < >; let eval = ()=>< >; let f = new Function('arguments', "'use strict'; return 1;");

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

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

Предположим, имеется следующий код:

const fn = function(a) < 'use strict'; a = 2; return [a, arguments[0]]; >console.log(fn(1))

В консоль попадёт [2,1] . Это так из-за того, что запись значения 2 в a не приводит к записи значения 2 в arguments[0] .

▍Оптимизации производительности

В строгом режиме не поддерживается свойство arguments.callee . В обычном режиме оно возвращает имя функции-родителя той функции, свойство callee объекта arguments которой мы исследуем.

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

В строгом режиме ключевое слово this не обязано всегда быть объектом. В обычных условиях, если this функции привязывается, с помощью call , apply или bind , к чему-то, что не является объектом, к значению примитивного типа вроде undefined , null , number или boolean , подобное значение должно быть объектом.

Если контекст this меняется на что-то, не являющееся объектом, его место занимает глобальный объект. Например — window . Это означает, что если вызвать функцию, установив её this в некое значение, не являющееся объектом, вместо этого значения в this попадёт ссылка на глобальный объект.

'use strict'; function fn() < return this; >console.log(fn() === undefined); console.log(fn.call(2) === 2); console.log(fn.apply(null) === null); console.log(fn.call(undefined) === undefined); console.log(fn.bind(true)() === true);

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

▍Изменения, имеющие отношение к безопасности

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

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

Эти возможности представляют собой потенциальную угрозу безопасности. В результате в строгом режиме доступ к этим свойствам запрещён.

function secretFunction() < 'use strict'; secretFunction.caller; secretFunction.arguments; >function restrictedRunner() < return secretFunction(); >restrictedRunner();

В предыдущем примере мы не можем, в строгом режиме, обратиться к secretFunction.caller и secretFunction.arguments . Дело в том, что эти свойства можно использовать для получения стека вызовов функции. Если попытаться запустить этот код — будет выдано исключение TypeError .

В строгом режиме для именования переменных или свойств объектов нельзя использовать идентификаторы, которые могут найти применение в будущих версиях JavaScript. Речь идёт, например, о следующих идентификаторах: implements , interface , let , package , private , protected , public , static и yield .

В ES2015 и в более поздних версиях стандарта эти идентификаторы стали зарезервированными словами. И их нельзя использовать для именования переменных или свойств в строгом режиме.

Итоги

Строгий режим — это стандарт, который существует уже многие годы. Он пользуется чрезвычайно широкой поддержкой браузеров. Проблемы с кодом, выполняемом в строгом режиме, могут возникать лишь у старых браузеров, таких, как Internet Explorer.

У современных браузеров не должно возникать сложностей со строгим режимом JavaScript. В результате можно сказать, что этот режим стоит использовать ради предотвращения «тихих» ошибок и ради повышения безопасности приложений. «Тихие» ошибки преобразуются в исключения, препятствующие выполнению программ, а в плане повышения безопасности можно, например, отметить механизмы строгого режима, ограничивающие eval и предотвращающие доступ к стеку вызовов функций. Кроме того, использование строгого режима облегчает оптимизацию кода JS-движками и заставляет программиста осторожно обращаться с зарезервированными словами, которые могут найти применение в будущих версиях JavaScript.

Уважаемые читатели! Пользуетесь ли вы строгим режимом при написании JS-кода своих проектов?

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *