Как вызвать функцию самоисполнения в JavaScript?

Когда у меня есть код, который мне нужно выполнить несколько раз, я завершаю его функцией, поэтому мне не нужно повторять. Иногда, кроме того, необходимо выполнить этот код изначально при загрузке страницы. Сейчас я делаю так:

function foo() {
   alert('hello');
}

foo();

Я бы предпочел сделать это следующим образом:

(function foo() {
   alert('hello');
})();

Проблема в том, что это будет выполняться только при загрузке страницы, но если я попытаюсь вызвать ее в последующие моменты времени с помощью foo(), это не сработает.

Я предполагаю, что это проблема с областью, но есть ли способ заставить себя выполнять функции, чтобы работать после вызова позже?

Ответ 1

Если ваша функция не полагается на возвращаемое значение, вы можете сделать это...

var foo = (function bar() {
   alert('hello');
   return bar;
})();   // hello

foo();  // hello

Здесь используется локальная ссылка bar в названном выражении функции для возврата функции к внешней переменной foo.


Или даже если это произойдет, вы можете сделать возвращаемое значение условным...

var foo = (function bar() {
   alert('hello');
   return foo ? "some other value" : bar;
})();   // hello

alert( foo() );  // hello --- some other value

или просто назначьте переменную вместо возврата...

var foo; 
(function bar() {
   alert('hello');
   foo = bar;
})();   // hello

foo();  // hello

Как отмечено @RobG, некоторые версии IE будут терять идентификатор в охватывающей области переменных. Этот идентификатор будет ссылаться на дубликат созданной вами функции. Чтобы сделать ваш NFE IE-safe (r), вы можете аннулировать эту ссылку.

bar = null;

Просто имейте в виду, что идентификатор по-прежнему будет затенять идентификатор с тем же именем в цепочке областей видимости. Обнуление не поможет, и локальные переменные не могут быть удалены, поэтому разумно выбирайте имя NFE.

Ответ 2

Чтобы вызываться извне, функция должна быть видна снаружи. В идеале у вас будет функция самоисполнения, которая вводит ее в некотором переданном контексте (в данном случае this, который ссылается на глобальный контекст):

(function(context) {
  var foo = function() {
    alert('hello');
  };
  foo();
  context.foo = foo;
})(this);

...

foo();

Более интересные шаблоны можно найти здесь.

Ответ 3

Если foo() предназначена для глобальной функции, то есть для свойства window, вы можете сделать это:

(window.foo = function() {
   alert('hello');
})();

// at some later time
foo();

Выражение в первом наборе скобок делает назначение для создания foo, но также оценивается как функция, поэтому вы можете немедленно вызвать его с помощью () в конце.

Этот шаблон работает, даже если функция должна возвращать значение.

Ответ 4

Вторая функция foo - выражение определения функции.

В выражении определения функции вы можете только вызвать функцию с именем внутри самой функции в соответствии с "Javascript: окончательное руководство":

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

Он может использоваться в выражении определения функции рекурсии.

Например:

var f = function factorial(n) {
    if (n == 0 || n == 1)
        return 1;
    else
        return n * factorial(n-1);
}