2012-06-05 31 views
11

Cuando tengo un código que necesito ejecutar más de una vez, lo cierro en una función para que no tenga que repetirlo. A veces, además, hay una necesidad de ejecutar este código inicialmente en la carga de la página. Ahora mismo lo hago de esta manera:¿Cómo llamar a una función autoejecutable en JavaScript?

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

foo(); 

yo prefiero hacerlo de esta manera:

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

El problema es que esto sólo se ejecutará al cargar la página, pero si trato de llamarlo tiempos posteriores usando foo() no funcionará.

Supongo que se trata de un problema de alcance, pero ¿hay alguna forma de que las funciones autoejecutables funcionen al recibir una llamada más tarde?

+1

No estoy seguro si esto es la mejor manera de hacerlo. Me imagino que esto se pondrá realmente complicado después de un tiempo. – Hassan

+3

Posible duplicado de http://stackoverflow.com/questions/6211466/call-immediately-executing-function-from-outside. – apsillers

+0

También posible duplicado de http://stackoverflow.com/questions/6404196/can-i-name-a-javascript-function-and-execute-it-immediately (que tiene mejores respuestas, en mi humilde opinión, pero la redacción de la pregunta es una coincidencia menos exacta). – apsillers

Respuesta

29

Si su función no se basa en un valor de retorno, se puede hacer esto ...

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

foo(); // hello 

Esto utiliza la referencia local bar en la expresión función llamada para devolver la función a la variable de foo externa .


O incluso si lo hace, usted podría hacer que el valor de retorno condicional ...

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

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

o simplemente asignar manualmente a la variable en lugar de volver ...

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

foo(); // hello 

Según lo observado por @RobG, algunas versiones de IE perderán el identificador en el ámbito de la variable adjunta. Ese identificador hará referencia a un duplicado de la función que creó. Para hacer su NFE IE-safe (r), puede anular esa referencia.

bar = null; 

Tenga en cuenta que el identificador seguirá sombreando un identificador con el mismo nombre en la cadena de alcance. Anular no ayudará, y las variables locales no se pueden eliminar, así que elija el nombre de NFE con prudencia.

+0

Las expresiones de funciones nombradas ** deberían ** ser muy útiles, pero están [rotas en IE] (http://kangax.github.com/nfe/#jscript-bugs), por lo que la mayoría las recomienda. p.ej. en el 'typeof bar' anterior muestra la" función "incluso si se coloca * antes de * el IIFE. – RobG

+0

@RobG: Es cierto, pero a menudo es un problema inocuo. El hecho de que 'bar' se filtre e incluso cree una función duplicada probablemente solo sea importante si está usando ese identificador en el alcance adjunto para hacer referencia a una variable más arriba en la cadena de alcance. –

+0

No es un problema aquí, pero generalmente la intención de las expresiones de función es mantener la función "privada". Permitir que se convierta en una función global puede tener consecuencias imprevistas, especialmente en proyectos más grandes. – RobG

4

Para llamar desde el exterior, la función debe ser visible desde el exterior. Lo ideal sería tener la función de auto ejecución de inyectarlo en algunos aprobada en contexto (en este caso, this, que hace referencia al contexto global):

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

... 

foo(); 

patrones más interesantes se pueden encontrar here.

+0

Buen enlace, gracias. – TK123

+1

Tendría más sentido pasar ' esto' ya que se garantiza que hace referencia al objeto global en el código global, 'window' no garantiza que haga referencia a nada, ni siquiera que se defina. – RobG

+0

@RobG: sí, sería :-) Acabo de proporcionar un ejemplo y he mencionado explícitamente _algunos pasaron en contexto_. Depende del OP decidir qué contexto será mejor para él. –

2

Si foo() pretende ser una función global, es decir, una propiedad de window, usted puede hacer esto:

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

// at some later time 
foo(); 

La expresión en el primer conjunto de paréntesis, hace la tarea de crear foo, sino también evalúa ser la función para que pueda invocarlo inmediatamente con () al final.

Este patrón funciona incluso si se supone que la función devuelve un valor.

+0

+1 No hay razón para que esto no se pueda hacer con los lugareños también. 'var foo; (foo = func ...})() ' –

+0

Gracias @amnotiam. Por supuesto, tienes razón acerca de los lugareños. Por alguna razón, cuando escribí esta respuesta, procuré mantenerla como una sola declaración y evitar una declaración var: ni siquiera recuerdo por qué ahora. – nnnnnn

0

La segunda función foo es una expresión de definición de función.

En una expresión de función definición, sólo puede llamar a la función con el nombre dentro de la propia función de acuerdo con "el Javascript la guía definitiva":

Para expresiones definición de función, el nombre es opcional: si está presente , el nombre se refiere al objeto de función solo dentro del cuerpo de la función en sí.

Se puede usar en una expresión de definición de función de recursión.

Por ejemplo:

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