2012-03-06 14 views
9

Todavía estoy confundido con el concepto de cierre en JavaScript. Me da el punto de que el cierre es la capacidad de la función interna para acceder a la variable creada dentro de su función madre después de que la función madre ha regresado. Pero todavía estoy confundido ¿por qué tenemos que crear una función interna para proteger la variable local si pudiéramos simplemente crear una variable dentro de la función?Javascript Cierres

+7

Un hermoso tutorial para Closure- https://developer.mozilla.org/en/JavaScript/Guide/Closures – Pranav

+0

Soy de la opinión de que este es el mejor artículo: http://javascript-reference.info/ javascript-closures-for-dummies.htm – Sang

Respuesta

1

La razón por la que necesita crear la función interna con variables de ámbito es la encapsulación orientada a objetos. Es esencialmente variables privadas.

Las variables están "cerradas".

// constructor function 
var myObject = function(message) { 
    // private - scope is function level. It's CLOSED OVER the the inner function (closure). 
    //   not delcared as a JSON property so not visible externally 
    var value = 0; 
    // constructor returns JSON object with public methods 
    // always constructed from the myObject var so it always hands back the same instance 
    // of the public methods 
    return { 
     // nested functions have access to outer function variables. 
     increment: function (inc) { 
      value ++; 
     }, 
     getValue: function() { 
      return value; 
     }, 
     // the inner function even has access to the outer function's args! 
     getMessage: message 
    } 
}; 

Mire la declaración de devolución. Devuelve la interfaz pública: algunos métodos que tienen acceso a la variable privada porque están en la función interna. Está utilizando la variable de ámbito de la función JavaScripts para crear encapsulación orientada a objetos.

Después de que puedo gustaría que:

var obj = myObject('Hello World'); 
obj.increment(); 
obj.increment(); 
console.log(obj.getValue()); 
console.log(obj.getMessage); 
// should be undefined 
console.log(obj.value); 

señalar en este punto que el consumidor no tiene acceso al valor protegido/encapsulado o un mensaje.

Ahora, aquí está el truco: el objeto es mutable para que la persona que llama pueda agregar métodos o incluso reemplazar los métodos. Entonces, pensarías que alguien podría agregar un método que exponga las partes internas. Pero no pueden debido al alcance de la función (cierre: están cerrados). Solo la función anidada tiene acceso a las variables de la función externa. Por lo tanto, si la persona que llama agrega un método para devolver el interno, no podrá obtener acceso y no estará definido.

El código anterior salidas:

2 
Hello World 
undefined 

Como nota al margen, estoy ejecutando el javascript con node.js

He aquí un buen blog sobre el patrón de módulo utilizando cierres:

http://www.yuiblog.com/blog/2007/06/12/module-pattern/

0

El punto es que la variable se comparte entre en las dos funciones. Si declaró la variable en la función interna, entonces la función externa no podría acceder a ella, por lo que no sería compartida.

+0

así que, incluso si la variable de la función interna está referenciada desde la variable de funciones madre, la variable de la función interna aún sería el valor cuando se modificó por última vez? – DevX

+0

Sí y no. No puede hacer referencia a las variables en la función interna desde la función externa, por lo que las variables internas mantienen sus valores. Pruebe el ejemplo de Sinetha con 'alerta (interno.foo) '(=> undefined) – Teemu

1

Usted acaba de responder su pregunta, la función interna protege su variable. jsFiddle

(function outer(){ 
    var foo = 'bar'; 
    function inner(){ 
     var foo = 'OMG NO!'; 
    } 
    alert(foo);//alerts 'bar' 
})() 
1

FROM MDN CLOSURES

why to use: 

Un cierre permite asociar unos datos (el medio ambiente) con una función que opera en esos datos. Esto tiene paralelismos obvios con la programación orientada a objetos, donde los objetos nos permiten asociar algunos datos (las propiedades del objeto) con uno o más métodos.

when not to use 

No es prudente para crear innecesariamente funciones dentro de otras funciones si no se necesitan cierres para una tarea en particular, ya que afectará negativamente al rendimiento de la escritura tanto en términos de velocidad de procesamiento y consumo de memoria.

Por ejemplo, cuando se crea un nuevo objeto/clase, los métodos normalmente deberían asociarse al prototipo del objeto en lugar de definirse en el constructor del objeto. La razón es que cada vez que se llama al constructor, los métodos se reasignarían (es decir, para cada creación de objeto).

0

Si declaró la variable en la función interna, cada llamada a la función interna crearía una nueva variable: cualquier modificación hecha por una llamada anterior se pierde.

Pero si la variable se declara en la función externa, varias llamadas a la función interna verán la misma variable y una llamada vería las modificaciones de una llamada anterior, siempre y cuando ambas tengan el mismo alcance que la función externa.

+0

Lo que quiere decir es que, incluso cuando llamo repetidamente a la función interna, la variable dentro de ella, a la que se hace referencia desde la variable creada por la función madre, aún se verá como se modificó cuando fue llamado previamente? Porque lo que tengo en mente es que la variable de la función interna aún tomará el valor de la variable de la función madre, al llamar a la función interna. – DevX

3

Necesitamos crear una función interna para que las variables en la función externa tengan alguna existencia después de que la función externa regrese.

Considérese una función simple:

function f() { 
    var x = 0; 
    return ++x; // x=1 
} // Once the function has exited then "x" no longer exists. 

Tenga en cuenta que la variable "x" sólo es "activo" (vivo, existente) cuando el control del programa fluye desde el inicio de la "f()" función hasta el final de eso Pero si adjuntamos "x" en una función interna entonces x vivirá siempre y cuando la función interna hace:

function g() { 
    var x = 0; 
    return function() { 
    // Now "x" will live for as long as this function. 
    return ++x; 
    } 
}; 
var counter = g(); 
counter(); // => 1 
counter(); // => 2 
counter(); // => 3 

Ahora, cuando nosotros llamamos "g()" tenemos otra función, y "x" está activo durante el tiempo que una variable haga referencia a esa función.

2

¿Por qué utilizar el cierre?

(function(){ 
    var current_page = 1; 
    function previous_page() { 
     current_page--; 
     // update interface 
    } 
    function next_page() { 
     current_page++; 
     // update interface 
    } 
    // a bit of jQuery, ok? 
    $('#previous').click(previous_page); 
    $('#next').click(next_page); 
})(); 

Look: no tenemos las variables globales, ni siquiera una función definida en el espacio global ... sin embargo, hemos adjuntado un comportamiento a los eventos de clic de botones "#previous" y "" para #next una función de búsqueda. ¿Cómo lo harías sin cierres? ¿Cómo lo harías definiendo la variable current_page dentro de las funciones?

+0

Puede codificar un objeto 'PageUpdater' para realizar un seguimiento de la página y actualizar la interfaz gráfica de usuario. Esto sería mucho más legible. Por supuesto, la variable de instancia sería visible para otros, ya que no hay ningún modificador de acceso para que sea privada. (Este es solo otro punto débil de JS y promueve código complejo extraño. –

0

Hay muchas respuestas correctas acerca de los cierres, pero siempre parece ser realmente técnico, mientras que muchas personas que preguntan podrían estar buscando una explicación simple de mayor nivel primero.

Me gusta pensar que es como un automóvil. Cuando maneja un automóvil, hay muchos procesos complejos en marcha, pero la persona promedio no necesita saber acerca de estos en un día normal. Piense en todas esas complejidades como variables "privadas" ocultas por cierres que hacen que el acelerador, el freno, la palanca de cambios, el volante, etc., sean mucho más fáciles de usar.

¿Cuál es el propósito de un cierre? Para ocultar todas las variables complejas y tal para hacer que un script sea mucho más útil. Si tuviera que preocuparse por cada variable en un script cada vez que quisiera usar alguna función en el script, eso podría volverse muy difícil. YAY CIERRE!