Недавно я столкнулся с некоторыми интересными фактами о именованных функциональных выражениях (NFE). Я понимаю, что имя функции NFE может быть доступно внутри тела функции, что делает рекурсию более удобной и экономит нам arguments.callee
. И имя функции недоступно вне тела функции. Например,
var foo = function bar() {
console.log(typeof bar);
};
typeof foo; // 'function'
typeof bar; // 'undefined', inaccessible outside the NFE
foo(); // 'function', accessible inside the NFE
Это хорошо задокументированная функция, и у kangax есть замечательный сообщение о NFE. и упомянул там это явление. Что меня больше всего удивляет, так это то, что имя функции NFE нельзя повторно связать с другими значениями в теле функции. Например,
(function foo() {
foo = 5;
alert(foo);
})(); // will alert function code instead of 5
В приведенном выше примере мы попытались повторно связать идентификатор foo
с другим значением 5
. Но это не удается! И я обратился к спецификации ES5 и обнаружил, что неизменяемая запись привязки была создана и добавлена в записи среды лексической среды при создании NFE.
Проблема в том, что когда NFE ссылается на собственное имя функции внутри тела функции, это имя разрешается как свободная переменная. В приведенном выше примере foo
упоминается внутри NFE, но это не формальный параметр и не локальная переменная этой функции. Таким образом, это свободная переменная, и ее запись привязки может быть разрешена через свойство [[scope]] NFE.
Итак, учтите, что если у нас есть другой идентификатор с тем же именем во внешней области видимости, возникает конфликт. Например,
var foo = 1;
(function foo() {
alert(foo);
})(); // will alert function code rather than 1
alert(foo); // 1
Когда мы выполняем NFE, свободная переменная foo
разрешается в функцию, с которой она связана. Но когда элемент управления выходит из контекста NFE, foo
разрешается как локальная переменная во внешней области.
Итак, мой вопрос заключается в следующем:
- Где хранится неизменяемая запись привязки имени функции?
- Почему имя функции
foo
перевешиваетvar foo = 1
при разрешении внутри NFE? Хранятся ли их записи связывания в одной и той же лексической среде? Если да, то как? - Что стоит за явлением, когда функция с именем
foo
доступна внутри, но невидима снаружи?
Может ли кто-нибудь пролить свет на это со спецификацией ES5? Я не нахожу большого обсуждения в Интернете.