Ответ 1
Функция AFAIK foo() {aaa(); } - это просто var foo = function() {aaa()} в JavaScript.
Это действительно неверно. JavaScript имеет два разных, но связанных друг с другом: объявления функций и выражения функций. Они происходят в разное время цикла синтаксического анализа и имеют разные эффекты.
Это объявление функции:
function foo() {
// ...
}
Объявления функций обрабатываются при входе в область приложения, перед выполнением любого пошагового кода.
Это выражение функции (в частности, анонимное):
var foo = function() {
// ...
};
Функциональные выражения обрабатываются как часть пошагового кода в точке, где они появляются (как и любое другое выражение).
В вашем цитируемом коде используется именованное выражение функции, которое выглядит следующим образом:
var x = function foo() {
// ...
};
(В вашем случае это внутри литерала объекта, поэтому оно находится в правой части :
вместо =
, но оно все еще является именованным функциональным выражением.)
Это совершенно корректно, игнорируя ошибки реализации (более мгновенно). Он создает функцию с именем foo
, не помещает foo
в область приложения, а затем назначает эту функцию переменной x
(все это происходит, когда выражение встречается в пошаговом режиме, код шага). Когда я говорю, что он не помещает foo
в охватывающую область, я имею в виду именно это:
var x = function foo() {
alert(typeof foo); // alerts "function" (in compliant implementations)
};
alert(typeof foo); // alerts "undefined" (in compliant implementations)
Обратите внимание, как это отличается от того, как работают объявления функций (где имя функции добавлено в область приложения).
Именованные функциональные выражения работают с совместимыми реализациями. Исторически сложилось так, что были ошибки в реализациях (раннее Safari, IE8 и ранее). Современные реализации дают им право, включая IE9 и выше. (Подробнее здесь: Double take и здесь: Именованные функциональные выражения demystified.)
Итак, в этом примере переменная
me
shoudl не будет разрешена изнутри методами
Собственно, это должно быть. Функциональное истинное имя (символ между function
и открывающей скобкой) всегда находится в области видимости внутри функции (независимо от того, является ли функция из объявления или имени функции).
ПРИМЕЧАНИЕ: ниже было написано в 2011 году. С достижениями в JavaScript с тех пор я больше не чувствую необходимости делать такие вещи, как ниже, если я не знаю, что я буду иметь дело с IE8 (что очень редко бывает в наши дни).
Из-за ошибок в реализации, я использовал, чтобы избежать именованных выражений функции. Вы можете сделать это в своем примере, просто удалив имена me
, но Я предпочитаю именованные функции, и поэтому для чего это стоит, здесь как я писал ваш объект:
var foo = (function(){
var publicSymbols = {};
publicSymbols.bar1 = bar1_me;
function bar1_me() {
var index = 1;
alert(bar1_me);
}
publicSymbols.bar2 = bar2_me;
function bar2_me() {
var index = 2;
alert(bar2_me);
}
return publicSymbols;
})();
(За исключением, вероятно, более короткого имени, чем publicSymbols
.)
Вот как это обрабатывается:
- Анонимная закрывающая функция создается, когда строка
var foo = ...
встречается в пошаговом коде, а затем она вызывается (потому что у меня есть()
в самом конце). - При входе в контекст выполнения, созданный этой анонимной функцией, обрабатываются декларации функций
bar1_me
иbar2_me
, и эти символы добавляются в область внутри этой анонимной функции (технически для объекта переменной для контекста выполнения). - Символ
publicSymbols
добавляется в область внутри анонимной функции. (Подробнее: Плохое непонятоеvar
) - Пошаговый код начинается с назначения
{}
publicSymbols
. - Пошаговый код продолжается с
publicSymbols.bar1 = bar1_me;
иpublicSymbols.bar2 = bar2_me;
и, наконец,return publicSymbols;
- Результат анонимной функции присваивается
foo
.
В наши дни, если я не пишу код, я знаю, что должен поддерживать IE8 (к сожалению, поскольку я пишу это в ноябре 2015 года, он все еще имеет значительный доля мирового рынка, но, к счастью, эта доля резко падает), я не беспокоюсь об этом. Все современные JavaScript-движки прекрасно понимают их.
Вы также можете записать это следующим образом:
var foo = (function(){
return {
bar1: bar1_me,
bar2: bar2_me
};
function bar1_me() {
var index = 1;
alert(bar1_me);
}
function bar2_me() {
var index = 2;
alert(bar2_me);
}
})();
... поскольку они являются декларациями функций и, таким образом, поднимаются. Обычно я этого не делаю, поскольку мне легче выполнять техническое обслуживание больших структур, если я делаю объявление и присваиваю свойство рядом друг с другом (или, если не писать для IE8, в той же строке).