2011-05-14 22 views
6

Crockford tenía este ejemplo para mantener miMatriz de ser en el ámbito global:No entiendo este ejemplo de un cierre

var myName = (function() { 
    var myArray = ['zero','one','two','three','four']; 
    return function(X) { 
     return myArray[X]; 
    } 
}()); // This function is invoked immediately 

result = myName(3); // Now invoke it "for real" 

Q: Yo no entiendo por qué no es

var myName = (function(X) { 

P: Cuando llamo a myName (3), ¿no se ejecuta "var myArray =" por segunda vez? Supongamos que no se ejecuta una segunda vez porque JavaScript sabe que ya se ha definido ... ¿Qué pasa con un bucle o alguna otra lógica entre la variable stmt y la función return? ¿No se ejecutará todo el tiempo?

P: ¿Puede nombrar la subfunción y llamarla en lugar de llamar a myName?

Respuesta

5

bien, vamos a descomponerlo ...

var myName = (function(){ 
    ... 
}()); 

esa pieza fija myName a lo que la función anónima rendimientos, por lo que si se tratara:

var myName = (function(){ return 42; }()); 

myName sería igual 42. Si eso no tiene sentido, esto es lo mismo:

function someFunction(){ return 42; } 
var myName = someFunction(); 

Así que en tu ejemplo, myName se establece en function(X){ return myArray[X] }. Entonces myName es una función. Cuando lo llamas, el único código que se ejecuta es return myArray[x].myArray se mantiene en lo que se llama cierre, solo está expuesto a la función myName y la anónima que lo rodea.

Escribí un artículo sobre cierres hace años que pueden ayudarle: http://www.htmlgoodies.com/primers/jsp/article.php/3606701/Javascript-Basics-Part-9.htm (desplácese hacia abajo al encabezado "Cierres").

+0

Estaba escribiendo una respuesta en el mismo sentido que esta, buena respuesta. – wambotron

+0

'myName' ** está ** establecido para ... (* usted no es *) –

+0

Creo que lo que quiere decir es 'var myName = someFunction;', no? – harpo

1

La función externa no tiene que tener un argumento X, porque su único propósito es devolver otra función (que luego se parametriza). Por lo tanto, no se necesita ningún argumento aquí.

Por lo tanto, el único efecto es vincular la cosa function(X)... a la variable myName. Por lo tanto, aquí no tiene sentido ningún otro constructo como bucles.

+0

"enlazar la función (X) ... a la variable myName". DE ACUERDO. Sí. –

0

Este enfoque garantiza que myArray solo se asigne una vez, cuando la función externa 'se invoque inmediatamente'. Después de que se invoca, myArray no está en el alcance global, pero todavía está disponible para la función interna anónima.

El enfoque que propuso funcionaría, pero requeriría que la matriz se asignara cada vez que se llamara a la función. (O puede asignarse fuera de la función, en el ámbito global.)

+0

No creo que sea correcto. –

+0

@cf_PhillipSenn No he encontrado ningún comentario útil. ¿Cuidado para elaborar? – edoloughlin

+0

Usted dijo que este enfoque "requeriría que la matriz se asignara cada vez que se llamara a la función", pero eso no es cierto. –

1

Q1 + 2: Observe el () a la derecha del comentario "Esta función se invoca inmediatamente". La función externa definida no se almacena en myName, sino que se llama inmediatamente. Sí mismo devuelve una función anónima que no tiene nombre y requiere un único parámetro (X). Esta función que se devuelve se almacena en myName.

Para captar el cierre, debe comenzar a pensar en las funciones como otro valor de una variable que puede almacenarse y devolverse jsut como cualquier otro valor.

Q3: myName es la subfunción.

+0

"empieza a pensar en las funciones como otro valor". Oh, –

+0

"myName es la subfunción". Ohhhh. –

1

respuesta bien a su vez:

En primer lugar, ¿por qué es var myName = (function() { y no var myName = (function(x) {

En este caso, ya que el valor x no es necesario para crear la función va a devolver. La estructura de datos de la matriz contenida en la función devuelta está codificada y por lo tanto no necesita información adicional para construirla. De la misma manera que

function a() { 
    return 1 + 2; 
} 

No tiene ningún argumento, porque sus valores están codificados. Este es un ejemplo de funciones como datos o first class functions

Pregunta dos: se ejecuta var myArray cada vez.

El cortocircuito es no. myArray ha sido asignado en este momento, por lo que tiene un valor que el sistema ya ha calculado. En este caso, es una función. La poción myArray se ha configurado y, por lo tanto, no hay motivo para seguir ejecutándola. Si la función externa no devolvió una nueva función, entonces sí debería llamarse una y otra vez, pero eso sería contrario al propósito de esta abstracción.

Pregunta tres: ¿puede llamar a la función interna.

No, está fuera de alcance. El punto entero de este ejemplo es que ha definido un generador de funciones.

+0

En realidad, puede nombrar la función interna siempre y cuando la exponga. Por ejemplo 'return (window.foo = function() {...})' funcionaría bien ya que es a lo que 'myName' se le está asignando. –

+0

Bueno, sí, pero eso cambia el alcance de la función. la forma en que está escrito no se puede simplemente decir return a = function (.... y luego llamar a – zellio

+0

más tarde No, la función aún tendría el alcance vinculado a la función anónima que lo envuelve. No tiene sentido en este ejemplo ya que 'myName' sería idéntico a' window.foo', pero estoy señalando que 'window.foo' funcionaría bien. Creo que estás confundiendo scope con el objeto padre (en este caso' window', por ejemplo "Namespace") de la función. El alcance solo es relevante para lo que la función tiene ___access___ to, no donde reside la función. –

3

OK aquí va .. respuesta a Q1. no es myName = (función (x) porque la parte dentro de los corchetes devuelve una función que toma X. ie mi nombre no está asignado a (función() {}) sino al valor de retorno.

Q2. No cuando llame a myName la segunda vez, ya apunta a la función interna, por lo tanto la función externa no se invoca en absoluto (esta es la separación de cierres donde el valor permanece activo en la función interna incluso si se completan las funciones externas)

Q3. Bien nopes podemos nombrar la función interna pero el nombre será válido solo dentro de la función externa y dado que la función externa ha completado el nombre sería inútil.

+1

"myname no está asignado a (function() {}) sino al valor de retorno de la misma". Está empezando a tener sentido ahora ... –

+0

@cf_PhillipSenn me alegro de ser de ayuda –

1

Respuesta a la primera pregunta: no, la primera "línea" está volviendo una función de modo que cuando se llama a "myName" en realidad está ejecutando la función devuelta

function(X) { 
     return myArray[X]; 
} 

respuesta a la segunda pregunta

no, una función de este tipo todavía se puede hacer referencia a la matriz "miMatriz" ... de hecho, el propósito de este cierre es hacer miMatriz disponibles en el ámbito global

+0

"así que cuando llamas a" miNombre "en realidad estás ejecutando la función devuelta." Entonces calcula todo, y luego almacena lo que está a la derecha de la devolver declaración en la memoria para que el fi La primera vez que se hace referencia, es una definición de función. DE ACUERDO. Creo que lo estoy entendiendo –

+0

dado que la función devuelta todavía se refiere a myArray, myArray permanece en la memoria y no se elimina al salir de la función principal ejecutada en la primera línea – SimonQuest

1

en palabras:

myName es el resultado de una función anónima inmediatamente ejecutada . Devuelve una referencia de función (a una función anónima). Esa función tiene un parámetro: X.Después de la ejecución de la función anónima más alta, myName es una referencia a la función anónima interna.

Ahora la función anónima interna tiene acceso a myArray a través de un cierre (myArray y la función anónima devuelta ambas viven dentro del alcance de la función anónima superior). Entonces, si ejecuta myName, realmente ejecuta la función anónima interna, que puede acceder al myArray.

La función anónima más alta se ejecuta inmediatamente y una vez (devuelve una referencia a la función interna). Entonces, myArray se declara dentro de ese contexto de ejecución, y solo una vez.

+0

"myName es el resultado de una función anónima ejecutada inmediatamente". Entonces myName ES la función anónima. Ohhh.No ejecuta la función anónima cada vez que se llama, es _IS_ la función anónima. Oooh. JavaScript es complicado. –

1

Dado que la definición del objeto myName (función) termina en '()', su función se llama inmediatamente, devolviendo una nueva función que tiene la variable myArray estáticamente vinculada a él. myName es accesible a nivel mundial, pero myArray no está como está dentro de un cierre de función. Cuando hace referencia a myName(), tiene acceso exclusivo a la matriz encuadernada.

+0

"myArray variable estáticamente vinculada a él". Como la declaración de variable STATIC en VB. Lo entiendo. –

+0

Sí, de eso se trata básicamente. Se puede hacer así porque en las funciones de JavaScript son de primera clase: ver http://en.wikipedia.org/wiki/First-class_function – KooiInc