1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
---
title: Переход к строгому режиму
slug: Web/JavaScript/Reference/Strict_mode/Transitioning_to_strict_mode
tags:
- Advanced
- JavaScript
translation_of: Web/JavaScript/Reference/Strict_mode/Transitioning_to_strict_mode
---
<div>{{jsSidebar("More")}}</div>
<p>В ECMAScript 5 введён {{jsxref('Strict_mode', 'строгий режим')}}, который реализован во всех основных браузерах (включая IE10). В то время как включение интерпретации браузерами кода в строгом режиме делается очень просто (достаточно добавить <code>"use strict";</code> в верхней части вашего исходного кода), для адаптации уже существующего кода к строгому режиму потребуется немного больше работы.</p>
<p>Цель этой статьи: предоставить для разработчиков руководство по переходу к строгому режиму.</p>
<h2 id="Постепенный_переход">Постепенный переход</h2>
<p>Строгий режим был спроектирован таким образом, чтобы переход к нему можно было сделать постепенно. Каждый файл можно переводить к строгому режиму поодиночке, и даже есть возможность включить строгий режим для каждой функции по отдельности.</p>
<h2 id="Различия_non-strict_и_strict_режимов">Различия non-strict и strict режимов</h2>
<h3 id="Синтаксические_ошибки">Синтаксические ошибки</h3>
<p>При добавлении <code>"use strict";</code> следующие случаи вызывают {{jsxref("SyntaxError")}} до выполнения скрипта:</p>
<ul>
<li>Восьмеричное представление числа <code>var n = 023;</code></li>
<li>Использование оператора <code>{{jsxref('Statements/with', 'with')}}</code></li>
<li>Использование <code>{{jsxref('Operators/delete', 'delete')}}</code> на имени переменной <code>delete myVariable;</code></li>
<li>Использование <code>{{jsxref('Global_Objects/eval', 'eval')}}</code> или <code>{{jsxref('Functions/arguments', 'arguments')}}</code> как переменную или аргумент функции</li>
<li>Использование одного из новых {{jsxref('Lexical_grammar', 'зарезервированных ключевых слов', 'Ключевые_слова')}} (зарезервированных для ECMAScript 6): <code>implements</code>, <code>interface</code>, <code>let</code>, <code>package</code>, <code>private</code>, <code>protected</code>, <code>public</code>, <code>static</code>, и <code>yield</code></li>
<li>Объявление функций в блоках <code>if (a < b) { function f() {} }</code></li>
<li>Очевидные ошибки
<ul>
<li>Объявление дважды свойства с одним и тем же именем в литерале объекта <code>{a: 1, b: 3, a: 7}</code>. Это уже изменилось в ECMAScript 6 ({{bug(1041128)}}).</li>
<li>Объявление нескольких аргументов функции с одним и тем же именем <code>function f(a, b, b) {}</code></li>
</ul>
</li>
</ul>
<p>Эти ошибки хороши тем, что обличают скользкие, едва уловимые ошибки и плохие практики написания кода.</p>
<h3 id="Новые_ошибки_времени_выполнения_runtime_errors">Новые ошибки времени выполнения (runtime errors)</h3>
<p>Ранее JavaScript не показывал никаких ошибок и предупреждений в некоторых случаях выполнения некорректного кода. Строгий режим выбрасывает исключения в таких случаях. Если в вашем коде есть такие случаи, тестирование будет необходимо, чтобы убедиться, что ничего не сломалось после перехода к строгому режиму. Ещё раз это может случится на уровне детализации функции.</p>
<h4 id="Установка_значения_необъявленной_переменной">Установка значения необъявленной переменной</h4>
<pre class="brush: js">function f(x) {
"use strict";
var a = 12;
b = a + x * 35; // error!
}
f(42);
</pre>
<p>Здесь изменяется значение глобального объекта, что редко является ожидаемым эффектом. Если вы действительно хотите изменить значение глобального объекта, передайте его в качестве аргумента функции и явно присвойте его как свойство:</p>
<pre class="brush: js">var global = this; // в верхнем контексте "this" всегда
// ссылается на глобальный объект
function f(x) {
"use strict";
var a = 12;
global.b = a + x * 35;
}
f(42);
</pre>
<h4 id="Попытка_удалить_неконфигурируемое_свойство">Попытка удалить неконфигурируемое свойство</h4>
<pre class="brush: js">"use strict";
delete Object.prototype; // error!
</pre>
<p>В нестрогом режиме этот код может молчаливо выполниться неудачей и ничего не сделать, вопреки ожиданиям.</p>
<h4 id="Отравленные_аргументы_arguments_и_свойства_функции">Отравленные аргументы (arguments) и свойства функции</h4>
<p>Обращение к <code>arguments.callee</code>, <code>arguments.caller</code>, <code>anyFunction.caller</code>, или <code>anyFunction.arguments</code> выбросит исключение в строгом режиме. Единственный законный способ повторного использования функции как в:</p>
<pre class="brush: js">// Пример взят из vanillajs: http://vanilla-js.com/
var s = document.getElementById('thing').style;
s.opacity = 1;
(function() {
if((s.opacity-=.1) < 0)
s.display = "none";
else
setTimeout(arguments.callee, 40);
})();</pre>
<p>может быть переписан как:</p>
<pre class="brush: js">"use strict";
var s = document.getElementById('thing').style;
s.opacity = 1;
(function fadeOut() { // имя функции
if((s.opacity-=.1) < 0)
s.display = "none";
else
setTimeout(fadeOut, 40); // используется имя функции
})();</pre>
<h3 id="Семантические_различия">Семантические различия</h3>
<p>Эти различия очень тонкие. Вполне возможно, что тесты не поймают этот тип едва уловимых отличий. Вероятно, потребуется тщательная рецензия кода, чтобы удостовериться, что эти различия не влияют на семантику вашего кода. К счастью, этот анализ может быть сделан постепенно, спускаясь вниз к реализации каждой конкретной функции.</p>
<h4 id="this_в_вызовах_функции"><code>this</code> в вызовах функции</h4>
<p>В функциях как <code>f()</code>, значением <code>this</code> является глобальный объект. В строгом режиме он теперь равен <code>undefined</code>. Когда функция вызывалась с помощью <code>{{jsxref('Global_Objects/Function/call', 'call')}}</code> или <code>{{jsxref('Global_Objects/Function/apply', 'apply')}}</code>, если значением был примитив, он упаковывался в соответствующий объект (или в глобальный объект для <code>undefined</code> и <code>null</code>). В строгом режиме значение передаётся без каких-либо преобразований и замен.</p>
<h4 id="arguments_не_является_псевдонимом_именованных_аргументов_функции"><code>arguments</code> не является псевдонимом именованных аргументов функции</h4>
<p>В нестрогом режиме изменение значения в объекте <code>arguments</code> изменяло соответствующий именованный аргумент функции. Это усложняло оптимизацию кода для движков JavaScript и сам код становился менее читабельным и понятным. В строгом режиме объект <code>arguments</code> создаётся и инициализируется с теми же значениями, что и именованные аргументы, но изменения объекта arguments или именованных аргументов теперь никак не влияют друг на друга.</p>
<h4 id="Изменения_в_eval">Изменения в <code>eval</code></h4>
<p>В строгом режиме eval не создаёт новой переменной в той области видимости, где был вызван. Также, конечно, в строгом режиме, строка выполняется с правилами строгого режима. Потребуется провести тщательное тестирование, чтобы убедиться, что ничего не сломалось. Не использовать eval, если он вам действительно не нужен, может быть другим прагматичным решением.</p>
<h2 id="Строго-нейтральный_код">Строго-нейтральный код</h2>
<p>Потенциальный "недостаток" перевода кода в строгий режим - это отличия в семантике старых браузеров, в которых он не реализован. В некоторых редких случаях (как при неудачной конкатенации и модификации) ваш код может не запускаться в режиме, в котором вы его писали и тестировали. Здесь несколько правил, как сделать ваш код строго-нейтральным (strictness-neutral):</p>
<ol>
<li>Пишите ваш код в строгом режиме и убедитесь в отсутствии ошибок только строго режима (из секции выше "Новые ошибки времени выполнения").</li>
<li>Держитесь подальше от семантических различий:
<ol>
<li><code>eval</code>: используйте только тогда, когда вы знаете что делаете</li>
<li><code>arguments</code>: всегда обращайтесь к аргументам функции через их имя или сделайте копию объекта arguments, используя:<br>
<code>var args = Array.prototype.slice.call(arguments)</code><br>
в самой первой строчке вашей функции</li>
<li><code>this</code>: используйте <code>this</code> только тогда, когда он ссылается на объект, созданный вами.</li>
</ol>
</li>
</ol>
<h2 id="Смотрите_также">Смотрите также</h2>
<ul>
<li>{{jsxref('Strict_mode', 'Строгий режим')}}</li>
</ul>
|