AFAIK function 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 и выше. (Подробнее здесь: Двойной дубль и здесь: Демистифицированные выражения именованных функций .)
Итак, в этом примере переменная me
не должна быть разрешена изнутри методами
На самом деле, так и должно быть. Истинное имя функции (символ между function
и открывающей скобкой) всегда находится внутри области действия (независимо от того, является ли функция объявлением или выражением именованной функции).
ПРИМЕЧАНИЕ : нижеследующее было написано в 2011 году. С достижениями в JavaScript с тех пор я больше не чувствую необходимости делать такие вещи, как ниже, если я не знаю, что буду иметь дело с IE8 ( что очень редко в наши дни).
Из-за ошибок в реализации я раньше избегал выражений именованных функций. Вы можете сделать это в своем примере, просто удалив me
names, но Я предпочитаю именованные функции , и поэтому, как это ни странно, вот как я писал ваш объект:
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
обрабатываются, и эти символы добавляются в область внутри этой анонимной функции (технически, в переменный объект *). 1093 * для контекста выполнения).
- Символ
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, в одной строке) .