Собственно, почему не функция, а только сам блок?
Проверено в Хроме, FF, IE11 и Опере 12.
function test() {
var e = 10, x = 5;
try {
console.log(e, x); // 10 5
throw 15;
} catch (e) {
var x;
console.log(e, x); // 15 5
e = x = 17;
console.log(e, x); // 17 17
} finally {
console.log(e, x); // 10 17
}
}
test();
Ну и ES6-версия с декомпозицией:
function test() {
var e = 10, x = 5;
try {
console.log(e, x); // 10 5
throw {e: 15, x:3};
} catch ({e, x}) {
console.log(e, x); // 15 3
e = x = 17;
console.log(e, x); // 17 17
} finally {
console.log(e, x); // 10 5
}
}
test();
Ответ
Обратимся к спецификации
Catch : catch ( CatchParameter ) Block
в oldEnv сохраняется LexicalEnvironment из текущего контекста
создается catchEnv как NewDeclarativeEnvironment(oldEnv)
для каждого имени аргумента из BoundNames в CatchParameter в catchEnv создается MutableBinding
текущим LexicalEnvironment в контексте устанавливается catchEnv
в status сохраняется результат BindingInitialization
если status не нормальный
текущим LexicalEnvironment в контексте устанавливается oldEnv
значением catch блока устанавливается значение status
В B сохраняется результат выполнения Block.
текущим LexicalEnvironment в контексте устанавливается oldEnv
значением catch блока устанавливается значение B
Что можно отметить в данном алгоритме?
при входе в catch создается новый LexicalEnvironment
значения указанные в параметрах catch связываются с новым LexicalEnvironment
при выходе - всегда восстанавливается старый LexicalEnvironment
Таким образом e объявленную выше var e=10 перекрывает e в выражении catch (e), значение которой и используется внутри блока.
И так как при выходе из блока восстанавливается старый LexicalEnvironment, внутри блока finally будет видна переменная объявленная через var.
Теперь можно перейти к вопросу из комментария:
@VladimirGamalian, а разве NewDeclarativeEnvironment не означает собственный скоуп? Но у catch'а ведь его нет? Или это такая магия за счёт всплытия объявлений, что всплывает всё кроме исключения? Как-то странно получается...
В контексте выполнения присутствуют два дополнительных свойства
LexicalEnvironment - определяет Lexical Environment, в котором хранятся идентификаторы созданные в коде в текущем контексте
VariableEnvironment - определяет Lexical Environment, в котором EnvironmentRecord хранит привязки созданные с помощью VariableStatements в текущем контексте
При использовании выражения var переменные добавляются в VariableEnvironment текущего контекста. Так как при заходе в catch меняется только LexicalEnvironment - то становится не важно в каком месте переменная объявлена с помощью var - она все равно будет добавлена в VariableEnvironment и будет доступна из любого места в текущем контексте выполнения.
Комментариев нет:
Отправить комментарий