2009-03-10 19 views
13

que estoy tratando de envolver mi cabeza alrededor de los cierres (Hay una broma en alguna parte) y me encontré con esto:alcance JavaScript y el cierre

(function() { /* do cool stuff */ })(); 

¿Cómo funciona esto? ¿Cuál es el propósito de poner la función en parens? ¿Por qué los parientes vacíos luego?

Respuesta

30

El punto de esto es que las variables declaradas en las cosas interesantes no se crearán en el espacio de nombres global. Cualquier función en javascript creará dicho alcance. Supongamos que tiene algún javascript que desea ejecutar. Si hace esto:

var b = 1; 
// stuff using b 

Y algún otro código utiliza b, obtendrá el valor que sobra. (O, lo que es peor, si algún otro código establece b antes de que se ejecute su código, luego intenta obtener su valor anterior más tarde, lo habría cambiado mientras tanto.)

Por otro lado, si tiene este código, que declara y después llama a la función:

function a() { 
    var b = 1; 
} 

a(); 

y algún otro código más adelante utiliza b, no va a ver a sus valores, ya que b es local a la función. El problema con esto, por supuesto, es que todavía estás haciendo un nombre global, "a", en este caso. Por lo tanto, queremos una función sin nombre: esta es la razón por la que obtienes el código que describes. Declara una función sin nombre, y luego la llama.

Por desgracia, no se puede simplemente decir:

function() { ... }() 

porque esto será analizado como una declaración de la función declaración, y luego un error de sintaxis. Al envolver la declaración de función entre paréntesis, obtiene una función expresión, que luego se puede llamar. Lo llama como cualquier otra expresión de función (como a, arriba), usando el segundo conjunto de parens. Por ejemplo, si la función tomara argumentos, los pasaría allí:

(function(a) { ... })(1) 
0

Ese constructo significa declarar una función anónima y ejecutarla inmediatamente. La razón por la que coloca su código dentro de un cuerpo de función es porque las variables que define dentro de él siguen siendo locales para la función y no como variables globales. Sin embargo, seguirán siendo visibles para los cierres definidos dentro de esta función.

1

Los paréntesis alrededor de la función dejan en claro que la función es una expresión. Los parens posteriores son la llamada a la función.

Observe que la función no tiene un nombre.

6

Eso crea una función, la llama y la descarta.

Podría ser más claro si nos fijamos en ello como esto:

var throwaway = function(){ 
    // do cool stuff 
}; 
throwaway(); 

Esto se hace para crear un espacio de nombres privado. El código en la función puede tener funciones y variables sin preocuparse de entrar en conflicto con otro código cargado en la página.

+3

Excepto, por supuesto, que entra en conflicto con el nombre de su función. –

+2

Uh, sí. Es por eso que normalmente se hace con una función anónima. Acabo de utilizar una función con nombre para mostrar una forma más familiar que hace lo mismo. –

+0

jder tiene la mejor respuesta para quienes llegan tarde a la fiesta. – Triptych

0

Al poner la declaración de función dentro de parens, se crea una expresión que evalúa la función anónima dentro. Por lo tanto, el primer paréntesis evalúa una función.

Los "parens vacíos" al final invocan la función definida, por lo que "// hacer cosas interesantes" se ejecuta inmediatamente.

Esta es una forma de ejecutar código sobre la marcha al tiempo que mantiene variables fuera del alcance global.

Lo que aquí se ilustra, sin embargo, no tiene nada que ver con los cierres, al menos no directamente. Los cierres consisten en mantener un ámbito léxico después de que una función primaria ya ha salido.

2

Acabo de encontrar esta publicación recientemente. Este tipo de función de definición & se llama autoinvocando funciones.

(function(){ //code })(); 

El código dentro de la función se ejecutará inmediatamente después de su definición.

1

Un enfoque es cierres para pasar variables a la función:

(function($, var_1, var_2) { 
    // use JQuery, var_1 and var_2 as local variables 
})($, var_1, var_2);