2011-12-13 16 views
11

Estaba viendo el sitio del desarrollador de Mozillas en el cierre de javascript y tenían este ejemplo de código.Devolución de funciones en javascript, comprensión del alcance y cierres

function makeAdder(x){ 
    return function (y) { 
     console.log(y + " this is y") 
     console.log(x + " this is x") 
     return x + y; 
     } 
} 
var add10 = makeAdder(10); 
console.log(add10(2)); // 12 

Ahora entiendo el atributo X que se está configurando, pero lo que no entiendo es cómo se ve afectado el alcance de la y. Sé que es una función de retorno, pero mi cerebro se fue a la mierda tratando de visualizar cómo se podía establecer una y cuando no había ningún ref. alguien podría explicar?

Respuesta

13

makeAdder devuelve una función a la que puede pasar el parámetro y. Se establece en el momento de la invocación, a diferencia de x que se establece en el momento de la creación de la nueva función (en el momento de la invocación de makeAdder).

Para el caso de este ejemplo, la salida es equivalente a haber escrito:

function add10(y) { 
    return 10 + y; 
} 

console.log(add10(2)); // 12 

Nada nuevo que está pasando aquí. El código de muestra intenta principalmente ilustrar que se está creando un cierre para x.

Así makeAdder, aquí, es bien llamado: cuando se pasa de 10 a ella, le da una función que agregará 10 a todo lo que pasa a la nueva función.

var add10 = makeAdder(10); 
var add20 = makeAdder(20); 

console.log(add10(1) + add20(1)); // 32 

Seguramente, con el propósito de añadir, podría ser más fácil simplemente tener una función que acepta dos parámetros y los añade. Pero esta no es una lección para agregar, es una lección de cierres.

un escenario del mundo real podría ser algo como esto:

var buttons = document.getElementsByClassName('myButton'); 
for(var i = 0; i < buttons.length; i++) { 
    buttons[i].onclick = function() { 
     alert('You clicked button ' + i); 
    }; 
} 

En el código anterior, i se han reiterado a través de todo el conjunto antes que cualquiera de los botones se hace clic. Por lo tanto, todos los botones alertarán sobre buttons.length. En su lugar, podría hacer lo siguiente:

var makeAlert = function(x) { 
    return function() { 
     alert('You clicked button ' + x); 
    }; 
}; 

for(var i = 0; i < buttons.length; i++) { 
    buttons[i].onclick = makeAlert(i); 
} 

La diferencia aquí es que i no está siendo utilizado cuando se hace clic en el botón (que será después de toda la iteración), pero se usa durante la iteración, en un momento en que i tendrá tiene un valor diferente para cada botón.

En lugar de crear una variable, makeAlert, verá a menudo este tipo de código que se escribe como una función anónima, invocado inmediatamente. El siguiente código es esencialmente equivalente al código anterior:

for(var i = 0; i < buttons.length; i++) { 
    buttons[i].onclick = (function(x) { 
     return function() { 
      alert('You clicked button ' + x); 
     }; 
    })(i); 
} 
+0

veo, mi cerebro todavía está tratando de conseguirlo, im tratando de ver cómo se pasa o se establece cuando no hay referencia, ya que add10 (3) en mi cabeza dice que su configuración X no es así ?? Esto parece bastante confuso :( – mustafa

+1

No, 'x' está establecido en' 10' en la llamada 'makeAdder (10)'. 'Y' está establecido en' 2' en la llamada 'add10 (2)'. –

+0

Pero no debería makeAdder (10, 2) ¿hace lo mismo? o ¿lo que estamos haciendo es básicamente makeAdder (10). (2)? muchas gracias chicos por cierto :) – mustafa

1

La función makeAdder devuelve una función cuando se invoca. Esta función que devuelve makeAdder acepta un parámetro; que se llama y.

La variable y existe solo durante la invocación de la función devuelta por makeAdder. Se crea cada vez que se llama y se destruye cuando la función regresa.

Por otra parte, se crea la variable x cuando se llama a makeAdder, y persiste debido al cierre creado por la función makeAdder devuelve. Se destruirá cuando no haya más referencias a la función devuelta.

1

Así add10 = makeAdder(10); es realmente regresan esta función:

function(y) { 
    console.log(y + " this is y") 
    console.log("10" + " this is x") 
    return 10 + y; 
} 

Entonces add10(2) está llamando a esa función, reemplazando y con 2 lados:

console.log("2" + " this is y") 
    console.log("10" + " this is x") 
    return 10 + 2; 
+0

Bien, pero ¿cómo sabes cuál es tu objetivo? Siento sonar tanto como un novato que estoy tratando de ver cómo sabrías que estás accediendo al parámetro correcto, creo que mi problema es entender cómo regresar. funciones en oposición a vars, etc. – mustafa

+0

Bueno, primero piense en reemplazar x por 10 en todas partes, y asigne esa función para agregar10. La primera vez que llama a makeAdded, se dirige a la primera función per se y la segunda vez a la función 'segundo', la que tiene y (que se anidó primero pero ahora se asigna a var y luego se llama beeing). Puede console.log (add10) en Firebug para verlo usted mismo después de realizar la tarea. – alessioalex

+0

Así que es un poco como escribir makeAdder (10). (2)? gracias muchachos por cierto :) – mustafa

2

Las funciones se pueden ver como objetos especiales que contienen código ejecutable y propiedades. Cada función tiene una propiedad especial [scope] que representa el entorno en el que se encontraba cuando se definió. Si se devuelve una función de otra función, esta nueva función cierra la referencia al entorno anterior en un "cierre".

por lo que cuando se llama a var add10 = makeAdder(10) lo que sucede es que la función devuelta x tiene el valor 10 que está ligado a su alcance, y la llamada console.log(add10(2)) impresiones 12.

Considere leer el artículo this para visualizar lo que son cierres. Se puede encontrar una explicación más detallada del cierre here.

+0

Gracias por el enlace amigo – mustafa

5

Lo que estamos pidiendo es una función que hace algo para usted:

function giveMeAFunctionThatBeeps(){ 
    return function() { 
     alert('Beep!'); 
     } 
} 

var beeper = giveMeAFunctionThatBeeps(); 

beeper(); // beeps! 

Los giveMeAFunctionThatbeeps reales es sólo una fábrica que le da una función que hace lo que quiere.

En el ejemplo que han proporcionado, estás haciendo lo mismo que el zumbador pero también estás pasando de un valor:

function giveMeAFunctionThatBeepsANumber(x){ 
    return function() { 
     alert('Beep ' + x); 
     } 
} 

Esto devuelve una señal sonora (que es una fábrica de recordar), pero el zumbador alerta el valor de x.

Sin embargo, este valor se establece cuando se crea la alarma:

var beeper = giveMeAFunctionThatBeeps(5); 

beeper(); // beeps 5! 

La señal acústica se ha quedado atascado pitar el valor 5 ahora, y no podemos hacer nada al respecto.

El siguiente ejemplo es si desea crear un localizador que emite un pitido cualquier número:

function giveMeAFunctionThatBeepsANumber(){ 
    return function (x) { 
     alert('Beep ' + x); 
     } 
} 

var beeper = giveMeAFunctionThatBeeps(); 

beeper(6); // beeps 6! 
beeper(7); // beeps 7! 

Como ahora estamos pidiendo a la fábrica para darnos una función que puede conectar un número en.

Entonces, por último, el ejemplo original, es a la vez de lo anterior combinado:

function giveMeAFunctionThatBeepsANumber(x){ 
    return function (y) { 
     alert('Beep ' + (x + y)); 
     } 
} 

var beeper = giveMeAFunctionThatBeeps(2); 

Cuando creamos el zumbador, estamos pasando en 2. Recuerde que el anterior, no podemos cambiar esto después! Siempre sonará 2 ...

...sino porque es una fábrica (preconfigurado con el valor 2) el retorno de una función que toma un parámetro, podemos personalizarlo cuando nos encontramos que:

beeper(6); // beeps 8! because x was set when we created it, and y is what we pass in. 
+0

Esto es excelente muchas gracias por su tiempo – mustafa

+0

No tengo preocupaciones, tuve problemas con los cierres y me encontré solo leyendo toneladas y toneladas de diferentes explicaciones para lo mismo ayudó :) – NibblyPig

Cuestiones relacionadas