#javascript #safari #scope
#javascript #safari #область видимости
Вопрос:
У нас есть что-то вроде этого
if(true) {
const a = 1;
function myFunc() {
alert(a);
}
myFunc();
}
В Safari 11 это вызывает "ReferenceError: Can't find variable: a"
.
Тот же код работает без ошибок в Chrome и Firefox.
Использование "strict mode"
в Safari решает проблему.
Я думаю, что основная проблема заключается в разной области действия const a
и function myFunc
. Последняя, по сути, является глобальной функцией из-за того, что условный оператор не создает область действия блока для функций внутри него (я полагаю, по устаревшим причинам), как это происходит для let и const .
Мне интересно, имеет ли Safari право в этом случае, потому что мы смешиваем вещи с разной областью видимости.
Есть ли какой-нибудь официальный ресурс, который объясняет этот случай? Я не нахожу упоминаний об этом поведении ни на сайтах caniuse, ни на mdn
Комментарии:
1. Взгляните на ecma-international.org/ecma-262/10.0 /…
Ответ №1:
Объявления функций внутри блоков не были определены в спецификации в течение многих лет, но они были разрешены различными движками javascript.
Поскольку этот синтаксис не был определен в спецификации и был разрешен движками javascript, разные движки выполняли разные действия. Некоторые сделали это синтаксической ошибкой, другие обработали объявления функций в областях блоков, поскольку они были выражениями функций. Некоторые движки обрабатывали объявления функций в области блока как несколько поднятых объявлений в одной области.
Начиная с ES2015, объявления функций являются частью спецификации, и существует два способа их обработки:
- Стандартная веб-семантика
- Устаревшая веб-семантика
Стандартная семантика
При стандартной семантике объявления функций преобразуются в выражения функций, объявляются с let
ключевым словом и помещаются в начало блока. Стандартная семантика действует в строгом режиме.
Таким образом, в строгом режиме ваш код будет обрабатываться движком javascript так, как если бы он был написан следующим образом:
if(true) {
let myFunc = function() {
alert(a);
}
const a = 1;
myFunc();
}
Устаревшая веб-семантика
В нестрогом режиме в браузерах применяется устаревшая веб-семантика. Когда объявления функций в области блока не рассматриваются как синтаксические ошибки, существует три сценария, которые обрабатываются одинаково всеми основными движками javascript. Эти три сценария:
- Функция объявляется и ссылается в одном блоке
- Функция объявлена и, возможно, используется в пределах одного блока, но также ссылается на определение внутренней функции, которое не содержится в этом же блоке.
- Функция объявлена и, возможно, используется в одном блоке, но также ссылается в последующих блоках.
В дополнение к let
переменной для функции, определенной в области блока, существует также переменная, определенная с помощью var
в области содержащей функции или глобальной области. Это var
присвоение не переносится в верхнюю часть блока и выполняется при достижении объявления функции в коде.
Ваш код в нестрогом режиме обрабатывается движком javascript как:
var varMyFunc;
if(true) {
let myFunc = function() {
alert(a);
}
const a = 1;
varMyFunc = myFunc; // at the place of function declaration
myFunc();
}
Вы не должны писать код, который полагается на устаревшую веб-семантику. Вместо этого используйте строгий режим, чтобы убедиться, что ваш код полагается на стандартные правила для обработки объявлений функций в областях блоков. Сказав все это, если у вас есть устаревший код в нестрогом режиме, который полагается на устаревшую веб-семантику, вы можете ожидать, что он будет работать в разных браузерах.