Простая функция JavaScript с немедленным вызовом не работает... почему?

Кто-нибудь может объяснить, почему это работает:

var sayHello = function (name) {
   alert("Hello there " + name + "!");
}("Mike");

Пока этого нет:

function sayHello (name) {
   alert("Hello there " + name + "!");
}("Mike");

Майк торф

6 ответов

Все, что вам нужно понять, это разница между FunctionExpression и FunctionDeclaration в Javascript.

Когда вы окружаете функцию круглыми скобками -

(function sayHello (name) {
   alert("Hello there " + name + "!");
})("Mike");

- Вы, технически, применяете к нему оператора группировки. После применения общее производство перестает быть FunctionDeclarataion, а является FunctionExpression. Сравнить -

function foo(){ } // FunctionDeclaration

(function foo(){ }); // FunctionExpresson
typeof function(){ }; // FunctionExpression
new function(){ }; // FunctionExpression

FunctionExpression (в отличие от FunctionDeclaration), как и любой другой MemberExpresson, может быть дополнен аргументами ("(" и ")") и приведет к вызову функции. Именно поэтому функция вызывается в вашем первом примере, а не во втором.

Обратите внимание, что функция FunctionExpression может иметь необязательные идентификаторы(в отличие от FunctionDeclaration, которые всегда должны иметь один), поэтому вы можете легко опустить "sayHello" и получить так называемое выражение анонимной функции -

(function(){
  alert('...');
});

Вы можете проверить мою статью о выражениях именованных функций, в которой более подробно рассматриваются тонкие детали различий между выражениями функций и объявлениями функций.

Ваш второй код на самом деле:

function sayHello (name) {
   alert("Hello there " + name + "!");
}

("Mike");

Итак, вы сначала объявляете функцию "sayHello", а затем выполняете "выражение":

("Mike");

который ничего не делает.

Это будет работать:

    (function sayHello (name) {
        alert("Hello there " + name + "!");
     })("Mike");

Обратите внимание на символы, заключающие в себе функцию. Вы также можете удалить имя функции "sayHello", и оно все равно будет работать. Насколько почему? Я не уверен. Может быть, это то, что, присваивая его переменной и не используя обертки (), вы фактически присваиваете его sayHello, а затем выполняете say hello, а не анонимную функцию.

var sayHello = function (name) {
   alert("Hello there " + name + "!");
}("Mike");

Это создает анонимную функцию и вызывает ее сразу с параметром "Mike". Затем возвращаемое значение этого вызова функции присваивается переменной sayHello,

function sayHello (name) {
   alert("Hello there " + name + "!");
}("Mike");

Это просто определяет нормальную функцию с именем sayHello и оператор функции заканчивается после закрытия}. Затем следует утверждение ("Майк"), которое является действительным, но ничего не делает.

Окружение определения функции в () перед звонком работает:

(function sayHello(name) {
   alert("Hello there " + name + "!");
})("Mike");

// however -- 
alert(typeof sayHello);  // undefined

Так что если вы хотите сделать что-то подобное - вы можете просто сделать это анонимной функцией:

(function(name) {
   alert("Hello there " + name + "!");
})("Mike");

И я не уверен, что это требуется - но для безопасности - всякий раз, когда я использую закрывающее устройство, я всегда оборачиваю его ()

Отредактировано, потому что мой ответ неправильно прочитал оригинальное сообщение:

Поскольку ваша функция больше не назначается как лямбда-функция для значения, последующий вызов функции с помощью ("Mike") не будет работать, так как нет значения для вызова. Как другие предлагали заключить в скобки, чтобы создать временную переменную, вы все равно сможете вызвать анонимную функцию:

(function sayHello (name) {
   alert("Hello there " + name + "!");
})('Mike');
Другие вопросы по тегам