Pregunta

¿Cómo explicar JavaScript cierres a alguien con un conocimiento de los conceptos que constan de (por ejemplo, funciones, variables y similares), pero no entiende cierres de sí mismos?

He visto el Esquema de ejemplo dado en la Wikipedia, pero por desgracia no ayuda.

¿Fue útil?

Solución

JavaScript cierres para principiantes

Enviado por Morris en mar, 2006-02-21 10:19.La comunidad editado desde entonces.

Los cierres no son magia

Esta página explica los cierres para que un programador puede entender con el trabajo de código JavaScript.No es para los gurús o funcional de los programadores.

Los cierres son no es difícil para entender de una vez el concepto central es grokked.Sin embargo, son imposibles de entender por la lectura de cualquier teórico o académico orientado explicaciones!

Este artículo está destinado a programadores con algo de experiencia en programación en un lenguaje corriente, y que puede leer la siguiente función JavaScript:

function sayHello(name) {
  var text = 'Hello ' + name;
  var say = function() { console.log(text); }
  say();
}
sayHello('Joe');

Dos breves resúmenes

  • Cuando una función (foo) declara otras funciones (bar y baz), la familia de variables locales se crean en foo es no se destruye cuando sale de la función.Las variables que más que convertirse en invisible para el mundo exterior. foo puede, por tanto, de astucia y de retorno de las funciones bar y baz, y se puede continuar a leer, escribir y comunicarse unos con otros a través de este cerrada-off de la familia de las variables ("el cierre") de que nadie puede inmiscuirse, ni siquiera alguien que se hace foo de nuevo en el futuro.

  • Un cierre es una forma de apoyar a de primera clase de las funciones;es una expresión que se puede hacer referencia a variables dentro de su ámbito de aplicación (cuando se fue declarado), ser asignado a una variable, se pasa como argumento a una función, o ser devuelto como resultado de la función.

Un ejemplo de un cierre

El código siguiente devuelve una referencia a una función:

function sayHello2(name) {
  var text = 'Hello ' + name; // Local variable
  var say = function() { console.log(text); }
  return say;
}
var say2 = sayHello2('Bob');
say2(); // logs "Hello Bob"

La mayoría de los programadores de JavaScript va a entender como una referencia a una función se devuelve en una variable (say2) en el código anterior.Si no, entonces usted necesita para mirar en que antes de que usted puede aprender los cierres.Un programador con C pensaría de la función que devuelve un puntero a una función, y que las variables say y say2 cada uno es un puntero a una función.

Hay una diferencia fundamental entre un C puntero a una función y una referencia de JavaScript a una función.En JavaScript, se puede pensar de una función de variable de referencia como la existencia de un puntero a una función así como oculta el puntero del clausura.

El código de arriba tiene un cierre debido a la función anónima function() { console.log(text); } se declara dentro de otra función, sayHello2() en este ejemplo.En JavaScript, si se utiliza el function palabras clave dentro de otra función, se crea un cierre.

En C y en la mayoría de los otros lenguajes comunes, después de una función devuelve, todas las variables locales no son accesibles porque la pila-marco es destruido.

En JavaScript, si se declara una función dentro de otra función, a continuación, las variables locales del exterior función puede seguir siendo accesible después de regresar de ella.Esto se demostró anteriormente, porque llamamos a la función say2() después de haber regresado de sayHello2().Observe que el código que nos llame hace referencia a la variable text, que fue un variable local de la función sayHello2().

function() { console.log(text); } // Output of say2.toString();

Buscando en la salida de say2.toString(), podemos ver que el código se refiere a la variable text.La función anónima puede hacer referencia a text que contiene el valor 'Hello Bob' debido a que las variables locales de sayHello2() han sido conservados con vida en un cierre.

El genio es que en JavaScript una función de referencia también tiene un secreto de referencia para el cierre fue creado en forma similar a cómo los delegados son un método puntero además de un secreto referencia a un objeto.

Más ejemplos

Por alguna razón, cierres parece realmente difícil de entender cuando usted lee acerca de ellos, pero al ver algunos ejemplos, queda claro cómo funcionan (me tomó un tiempo).Recomiendo trabajar a través de los ejemplos cuidadosamente hasta que entiendan cómo funcionan.Si usted comienza a utilizar los cierres sin entender completamente cómo funcionan, que pronto iba a crear algunos muy extraños bichos!

Ejemplo 3

Este ejemplo muestra que las variables locales no son copiadas de que se mantienen por referencia.Es como si la pila-marco se mantiene vivo en la memoria incluso después de que el exterior de la función de las salidas!

function say667() {
  // Local variable that ends up within closure
  var num = 42;
  var say = function() { console.log(num); }
  num++;
  return say;
}
var sayNumber = say667();
sayNumber(); // logs 43

Ejemplo 4

Los tres funciones globales tienen una referencia común a la mismo cierre porque todos son declaradas dentro de una sola llamada a setupSomeGlobals().

var gLogNumber, gIncreaseNumber, gSetNumber;
function setupSomeGlobals() {
  // Local variable that ends up within closure
  var num = 42;
  // Store some references to functions as global variables
  gLogNumber = function() { console.log(num); }
  gIncreaseNumber = function() { num++; }
  gSetNumber = function(x) { num = x; }
}

setupSomeGlobals();
gIncreaseNumber();
gLogNumber(); // 43
gSetNumber(5);
gLogNumber(); // 5

var oldLog = gLogNumber;

setupSomeGlobals();
gLogNumber(); // 42

oldLog() // 5

Las tres funciones tienen acceso compartido a la misma — cierre las variables locales de setupSomeGlobals() cuando las tres funciones que se han definido.

Tenga en cuenta que en el ejemplo anterior, si la llamada setupSomeGlobals() de nuevo, a continuación, un nuevo cierre (pila-¡marco!) es creado.El viejo gLogNumber, gIncreaseNumber, gSetNumber las variables se sobrescriben con nuevo las funciones que tiene el nuevo cierre.(En JavaScript, cuando se declara una función dentro de otra función, dentro de la función(s) es/son recreados de nuevo cada el tiempo fuera se llama a la función.)

Ejemplo 5

Este ejemplo muestra que el cierre contiene las variables locales que fueron declaradas en el exterior de la función antes de salir.Tenga en cuenta que la variable alice en realidad es declarado después de la función anónima.La función anónima se declara primero y cuando se llama a la función se puede acceder a la alice variable porque alice es en el mismo ámbito (JavaScript ¿ variable de elevación).También sayAlice()() sólo llama directamente a la función de referencia regresó de sayAlice() — es exactamente lo mismo como lo que se hizo anteriormente, pero sin la variable temporal.

function sayAlice() {
    var say = function() { console.log(alice); }
    // Local variable that ends up within closure
    var alice = 'Hello Alice';
    return say;
}
sayAlice()();// logs "Hello Alice"

Complicado:nota la say variable también está dentro de la clausura y puede ser visitada por cualquier otra función que pueda ser declarada dentro de sayAlice(), o se podría acceder de forma recursiva en el interior de la función.

Ejemplo 6

Este es un verdadero problema para muchas personas, por lo que necesita para entenderlo.Ser muy cuidadoso al definir una función dentro de un bucle:las variables locales a partir de la clausura no puede actuar como usted podría pensar.

Usted necesita entender la variable de "elevación" en función de Javascript con el fin de entender este ejemplo.

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
        var item = 'item' + i;
        result.push( function() {console.log(item + ' ' + list[i])} );
    }
    return result;
}

function testList() {
    var fnlist = buildList([1,2,3]);
    // Using j only to help prevent confusion -- could use i.
    for (var j = 0; j < fnlist.length; j++) {
        fnlist[j]();
    }
}

 testList() //logs "item2 undefined" 3 times

La línea result.push( function() {console.log(item + ' ' + list[i])} agrega una referencia a una función anónima tres veces a la matriz de resultados.Si usted no está tan familiarizado con las funciones anónimas pensar en ella como:

pointer = function() {console.log(item + ' ' + list[i])};
result.push(pointer);

Tenga en cuenta que al ejecutar el ejemplo, "item2 undefined" se registra tres veces!Esto es porque al igual que los ejemplos anteriores, sólo hay un cierre para las variables locales para buildList (que son result, i, list y item).Cuando las funciones anónimas son llamados en la línea fnlist[j]();todos ellos utilizan el mismo cierre, y utilizan el valor actual de i y item dentro de aquel cierre (donde i tiene un valor de 3 debido a que el bucle se había completado, y item tiene un valor de 'item2').Nota que estamos de indexación de 0 por lo tanto item tiene un valor de item2.Y la i++ se incrementará i para el valor 3.

Puede ser útil para ver lo que ocurre cuando un bloque de declaración de nivel de la variable item se usa (a través de la let palabra clave) en lugar de una función del ámbito de la declaración de variable a través de la var la palabra clave.Si el cambio se hizo, luego de cada función anónima en la matriz result tiene su propio cierre;cuando se ejecuta el ejemplo el resultado es como sigue:

item0 undefined
item1 undefined
item2 undefined

Si la variable i se define también el uso de let en lugar de var, entonces la salida es:

item0 1
item1 2
item2 3

Ejemplo 7

En este último ejemplo, cada llamada a la función principal crea un cierre.

function newClosure(someNum, someRef) {
    // Local variables that end up within closure
    var num = someNum;
    var anArray = [1,2,3];
    var ref = someRef;
    return function(x) {
        num += x;
        anArray.push(num);
        console.log('num: ' + num +
            '; anArray: ' + anArray.toString() +
            '; ref.someVar: ' + ref.someVar + ';');
      }
}
obj = {someVar: 4};
fn1 = newClosure(4, obj);
fn2 = newClosure(5, obj);
fn1(1); // num: 5; anArray: 1,2,3,5; ref.someVar: 4;
fn2(1); // num: 6; anArray: 1,2,3,6; ref.someVar: 4;
obj.someVar++;
fn1(2); // num: 7; anArray: 1,2,3,5,7; ref.someVar: 5;
fn2(2); // num: 8; anArray: 1,2,3,6,8; ref.someVar: 5;

Resumen

Si todo parece estar completamente claro, entonces la mejor cosa a hacer es jugar con los ejemplos.La lectura de una explicación es mucho más difícil que la comprensión de los ejemplos.Mis explicaciones de los cierres y de pila de cuadros, etc.no son técnicamente correcta — son groseras simplificaciones, diseñada para ayudar a entender.Una vez que la idea básica es grokked, usted puede recoger los detalles más tarde.

Puntos finales:

  • Siempre que usted use function dentro de otra función, un cierre se utiliza.
  • Siempre que usted use eval() dentro de una función, de un cierre se utiliza.El texto que eval puede hacer referencia a las variables locales de la función, y dentro de eval usted puede incluso crear nuevas variables locales mediante el uso de eval('var foo = …')
  • Cuando se utiliza new Function(…) (el La función de constructor) dentro de una función, no se crea un cierre.(La nueva función no puede hacer referencia a las variables locales del exterior de la función.)
  • Un cierre en JavaScript es como la de mantener una copia de todas las variables locales, tal como lo fueron cuando la función terminó.
  • Es probablemente el mejor para pensar que un cierre siempre se crea sólo una entrada para una función, y las variables locales se agrega que el cierre.
  • Un nuevo conjunto de variables locales se mantiene cada vez que una función con un cierre a la llama (dado que la función contiene una declaración de función en su interior, y una referencia a que dentro de la función se le devuelve o una referencia externa se mantiene de alguna manera).
  • Dos funciones que podría parecer tienen el mismo texto de origen, pero han comportamiento completamente diferente debido a su "oculto" de cierre.No creo que el código JavaScript en realidad puede averiguar si una función de referencia tiene un cierre o no.
  • Si usted está tratando de hacer alguna dinámica de modificaciones del código fuente (por ejemplo: myFunction = Function(myFunction.toString().replace(/Hello/,'Hola'));), no va a funcionar si myFunction es un cierre (por supuesto, usted nunca incluso pensar en hacer el código fuente de la cadena de sustitución en tiempo de ejecución, pero...).
  • Es posible obtener declaraciones de función dentro de las declaraciones de función dentro de las funciones... y usted puede conseguir cierres en más de un nivel.
  • Creo que normalmente un cierre es un término de la función, junto con las variables que son capturados.Tenga en cuenta que yo no uso esa definición en este artículo!
  • Tengo la sospecha de que los cierres en JavaScript difieren de los que normalmente se encuentran en los lenguajes funcionales.

Enlaces

Gracias

Si usted tiene sólo aprendido cierres (aquí o en otra parte!), a continuación, estoy interesado en cualquier información de usted acerca de cualquier cambio que podría sugerir que podría hacer este artículo más claro.Enviar un correo electrónico a morrisjohns.com (morris_closure @).Por favor, tenga en cuenta que no soy un gurú en JavaScript — ni en los cierres.


Post Original por Morris se puede encontrar en el Internet Archive.

Otros consejos

Cuando vea la palabra clave de función dentro de otra función, el interior de la función tiene acceso a las variables en el exterior de la función.

function foo(x) {
  var tmp = 3;

  function bar(y) {
    console.log(x + y + (++tmp)); // will log 16
  }

  bar(10);
}

foo(2);

Esto será siempre de registro de 16, porque bar puede acceder a la x que fue definido como un argumento para foo, y también puede acceder a tmp de foo.

Que es un cierre.Una función no tiene que volver con el fin de ser llamado un cierre. Simplemente el acceso a las variables fuera de su inmediata ámbito léxico crea un cierre.

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + (++tmp)); // will also log 16
  }
}

var bar = foo(2); // bar is now a closure.
bar(10);

La función anterior será también de registro de 16, porque bar todavía puede referirse a x y tmp, aunque no es directamente dentro del ámbito de aplicación.

Sin embargo, desde tmp se sigue dando vueltas en el interior de bar's de cierre, también se incrementa.Será incrementado cada vez que se llama a bar.

El ejemplo más simple de un cierre a este:

var a = 10;

function test() {
  console.log(a); // will output 10
  console.log(b); // will output 6
}
var b = 6;
test();

Cuando una función de JavaScript que se invoca, un nuevo contexto de ejecución se crea.Junto con los argumentos de la función y el objeto primario, este contexto de ejecución también recibe todas las variables declaradas fuera de ella (en el ejemplo anterior, tanto 'a' y 'b').

Es posible crear más de un cierre de función, devolviendo una lista de ellos o por ajuste a las variables globales.Todos estos se refieren a la mismo x y el mismo tmp, ellos no hacen sus propias copias.

Aquí el número de x es un número literal.Como con otros literales en JavaScript, cuando foo se llama, el número de x es copiado en foo como argumento x.

Por otro lado, JavaScript siempre utiliza referencias a la hora de tratar con objetos.Si decir, que se llama foo con un objeto, en el cierre, se le devuelve referencia que el objeto original!

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + tmp);
    x.memb = x.memb ? x.memb + 1 : 1;
    console.log(x.memb);
  }
}

var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);

Como era de esperar, cada llamada a bar(10) se incrementará x.memb.Lo que no se puede esperar, es que x es, simplemente, que hacen referencia al mismo objeto como el age variable!Después de un par de llamadas a bar, age.memb será el 2!Esta referencia es la base para pérdidas de memoria con objetos HTML.

PRÓLOGO:esta respuesta fue escrito cuando la pregunta fue:

Como el viejo Albert dijo :"Si no puedes explicarlo a un niño de seis años de edad, usted realmente no entiende a ti mismo.".Bueno, yo traté de explicar JS cierres a un 27 años de edad amigo y fracasado totalmente.

¿Alguien puede considerar que estoy de 6 y extrañamente interesados en el tema ?

Estoy bastante seguro de que era una de las personas que intentaron llevar a la pregunta inicial, literalmente.Desde entonces, la cuestión ha mutado varias veces, así que mi respuesta ahora puede parecer increíblemente tonto y fuera de lugar.Esperemos que la idea general de la historia sigue siendo divertido para algunos.


Soy un gran fan de la analogía y la metáfora a la hora de explicar conceptos difíciles, así que déjame probar mi mano con una historia.

Érase una vez:

Había una princesa...

function princess() {

Ella vivía en un mundo maravilloso lleno de aventuras.Ella conoció a su Príncipe Encantador, se montó alrededor de su mundo en un unicornio, luchó contra los dragones, se encontró hablando de animales, y muchas otras cosas fantásticas.

    var adventures = [];

    function princeCharming() { /* ... */ }

    var unicorn = { /* ... */ },
        dragons = [ /* ... */ ],
        squirrel = "Hello!";

    /* ... */

Pero ella siempre se tiene que volver a su mundo aburrido de las tareas domésticas y de adultos.

    return {

Y a menudo hablaba de su última aventura increíble como una princesa.

        story: function() {
            return adventures[adventures.length - 1];
        }
    };
}

Pero todos los que iban a ver es una niña...

var littleGirl = princess();

...contar historias acerca de la magia y la fantasía.

littleGirl.story();

Y aunque los adultos sabían de auténticas princesas, nunca iba a creer en los unicornios o dragones ya que nunca pudieron ver.Los adultos dijo que sólo existía en el interior de la niña de la imaginación.

Pero nosotros sabemos la verdad real;que la niña con la princesa en el interior...

...es realmente una princesa con una niña dentro.

Tomando la cuestión en serio, debemos averiguar lo que es un típico niño de 6 años es capaz de cognitivamente, aunque es cierto que, quien esté interesado en JavaScript no es tan típico.

En Desarrollo De La Primera Infancia:De 5 a 7 Años dice:

Su hijo será capaz de seguir las indicaciones de dos pasos.Por ejemplo, si le dice a su hijo: "Ve a la cocina y me dio una bolsa de basura" que será capaz de recordar esa dirección.

Podemos utilizar este ejemplo para explicar los cierres, de la siguiente manera:

La cocina es un cierre que tiene una variable local, llamado trashBags.Hay una función dentro de la cocina se llama getTrashBag que se pone una bolsa de basura y se la devuelve.

Podemos este código en JavaScript como este:

function makeKitchen() {
  var trashBags = ['A', 'B', 'C']; // only 3 at first

  return {
    getTrashBag: function() {
      return trashBags.pop();
    }
  };
}

var kitchen = makeKitchen();

console.log(kitchen.getTrashBag()); // returns trash bag C
console.log(kitchen.getTrashBag()); // returns trash bag B
console.log(kitchen.getTrashBag()); // returns trash bag A

Más puntos que explican por qué los cierres son interesantes:

  • Cada vez que makeKitchen() se llama, un nuevo cierre se crea independiente con su propia trashBags.
  • El trashBags variable es local en el interior de cada cocina y no es accesible desde fuera, pero el interior de la función en el getTrashBag la propiedad tiene acceso a él.
  • Cada llamada a la función, se crea un cierre, pero no habría ninguna necesidad de mantener el cierre de alrededor de menos de un interior de la función, que tiene acceso al interior de la clausura, se puede llamar desde fuera de la clausura.Devolver el objeto con el getTrashBag función que aquí.

El Hombre De Paja

Necesito saber el número de veces que el botón ha sido pulsado y hacer algo en cada tercer haga clic en...

Bastante Obvio Solución

// Declare counter outside event handler's scope
var counter = 0;
var element = document.getElementById('button');

element.addEventListener("click", function() {
  // Increment outside counter
  counter++;

  if (counter === 3) {
    // Do something every third time
    console.log("Third time's the charm!");

    // Reset counter
    counter = 0;
  }
});
<button id="button">Click Me!</button>

Ahora esto va a funcionar, pero no inmiscuirse en el exterior del ámbito de aplicación mediante la adición de una variable, cuyo único propósito es mantener el seguimiento de la cuenta.En algunas situaciones, esto sería preferible como la capa externa de la aplicación de la necesidad de tener acceso a esta información.Pero en este caso, sólo estamos cambiando cada tercer haga clic en la conducta, por lo que es preferible incluir esta funcionalidad en el controlador de eventos.

Considerar esta opción

var element = document.getElementById('button');

element.addEventListener("click", (function() {
  // init the count to 0
  var count = 0;

  return function(e) { // <- This function becomes the click handler
    count++; //    and will retain access to the above `count`

    if (count === 3) {
      // Do something every third time
      console.log("Third time's the charm!");

      //Reset counter
      count = 0;
    }
  };
})());
<button id="button">Click Me!</button>

Aviso un par de cosas aquí.

En el ejemplo de arriba, estoy utilizando el cierre de comportamiento de JavaScript. Este comportamiento permite que cualquier función para tener acceso al ámbito en el que fue creado, de forma indefinida. Aplicar prácticamente esto, inmediatamente me invocar una función que devuelve otra función, y debido a que la función me estoy volviendo tiene acceso a la interna de la variable de conteo (por el cierre de comportamiento se explicó anteriormente) esto se traduce en un ámbito privado para uso por el resultado de la función...No es tan simple?Vamos a diluir abajo...

Una simple línea de cierre

//          _______________________Immediately invoked______________________
//         |                                                                |
//         |        Scope retained for use      ___Returned as the____      |
//         |       only by returned function   |    value of func     |     |
//         |             |            |        |                      |     |
//         v             v            v        v                      v     v
var func = (function() { var a = 'val'; return function() { alert(a); }; })();

Todas las variables fuera de la función devuelto están disponibles para la función devuelto, pero que no están directamente disponibles para la devuelve el objeto de la función...

func();  // Alerts "val"
func.a;  // Undefined

Conseguirlo?Así, en nuestro ejemplo, la variable de conteo está contenida dentro de la clausura y siempre disponible para el controlador de eventos, por lo que conserva su estado de haga clic en haga clic en.

Además, esta variable privada del estado es totalmente accesible, tanto para las lecturas y la asignación a su privado el ámbito de las variables.

Hay que ir;usted ahora está completamente encapsulado de este comportamiento.

Blog Completo (incluyendo jQuery consideraciones)

Los cierres son difíciles de explicar, ya que se utilizan para hacer algunas actitudes de trabajo que todo el mundo intuitivamente se espera trabajar de todos modos.Me parece la mejor manera de explicar (y la forma en que Yo se enteró de lo que hacen), es de imaginar la situación sin ellos:

    var bind = function(x) {
        return function(y) { return x + y; };
    }
    
    var plus5 = bind(5);
    console.log(plus5(3));

¿Qué pasaría aquí si JavaScript no conozca los cierres?Basta con sustituir la llamada en la última línea de su cuerpo de método (que es básicamente lo que la función de llamadas) y se obtiene:

console.log(x + 3);

Ahora, ¿dónde está la definición de x?No hemos de definir en el ámbito actual.La única solución es dejar que plus5 llevar su ámbito de aplicación (o más bien, su padre el ámbito de aplicación) de todo.De esta manera, x está bien definido y es enlazado con el valor 5.

Este es un intento de aclarar varios (posible) de los malentendidos acerca de los cierres de los que aparecen en algunas de las otras respuestas.

  • Un cierre que no sólo se crea cuando regrese interior de la función. De hecho, la que encierra la función no es necesario volver a todos en orden para su cierre, a ser creado.Usted puede en lugar de asignar su interior la función a una variable en un alcance externo, o pasar como argumento a otra función que podría ser llamado inmediatamente o en cualquier momento posterior.Por lo tanto, el cierre de la adjuntando función es, probablemente creado tan pronto como el adjuntando se llama a la función desde cualquier interior función tiene acceso a que se cierre cuando el interior se llama a la función, antes o después de la envolvente función devuelve.
  • Un cierre no hace referencia a una copia de la los viejos valores de las variables en su ámbito de aplicación. Las variables que sí son parte de la clausura, y así el valor que se ve al entrar a una de esas variables es el valor más reciente en el momento en que se acceda.Esta es la razón por la interna de funciones creadas dentro de bucles puede ser complicado, ya que cada uno tiene acceso a las mismas variables externas en lugar de agarrar una copia de las variables en el momento de crear la función o llamado.
  • Las "variables" en un cierre de incluir cualquiera de las funciones con nombre declaradas dentro de la función.Se incluyen también los argumentos de la función.Un cierre también tiene acceso a la contienen cierre de las variables, todo el camino hasta el ámbito global.
  • Cierres de uso de memoria, pero no causan pérdidas de memoria desde JavaScript por sí limpia sus propias estructuras circulares que no se hace referencia.Internet Explorer pérdidas de memoria que implican los cierres son creadas cuando se produce un error para desconectar DOM valores de atributos que hacen referencia a los cierres, manteniendo así las referencias a posiblemente estructuras circulares.

OK, de 6 años, cierres de ventilador.¿Quieres oír el ejemplo más simple de cierre?

Imaginemos la siguiente situación:un conductor está sentado en un coche.Que el coche está dentro de un avión.Es un plano en el aeropuerto.La capacidad de controlador para tener acceso a las cosas fuera de su coche, pero en el interior del avión, incluso si el avión sale de un aeropuerto, es un cierre.Eso es todo.Cuando encienda 27, mira el explicación más detallada o en el ejemplo de abajo.

Aquí es ¿cómo puedo convertir mis plano de la historia en el código.

var plane = function(defaultAirport) {

  var lastAirportLeft = defaultAirport;

  var car = {
    driver: {
      startAccessPlaneInfo: function() {
        setInterval(function() {
          console.log("Last airport was " + lastAirportLeft);
        }, 2000);
      }
    }
  };
  car.driver.startAccessPlaneInfo();

  return {
    leaveTheAirport: function(airPortName) {
      lastAirportLeft = airPortName;
    }
  }
}("Boryspil International Airport");

plane.leaveTheAirport("John F. Kennedy");

Un cierre se parece mucho a un objeto.Se pone instancia cada vez que se llama a una función.

El alcance de un cierre en JavaScript es léxica, lo que significa que todo lo que está contenido dentro de la función de la cierre pertenece a, se tiene acceso a cualquier variable que está en él.

Una variable es incluida en el cierre si

  1. asignar con var foo=1; o
  2. acaba de escribir var foo;

Si un interno de la función (una función dentro de otra función) accede a este tipo de variable sin definir en su propio ámbito con el var, se modifica el contenido de la variable en el exterior cierre.

Un cierre deja de ser el tiempo de ejecución de la función que le dio origen.Si otras funciones que hacen de la cierre/alcance en el que se han definido (por ejemplo, como valores de retorno), los seguirán haciendo referencia a que cierre.

Ejemplo

function example(closure) {
  // define somevariable to live in the closure of example
  var somevariable = 'unchanged';

  return {
    change_to: function(value) {
      somevariable = value;
    },
    log: function(value) {
      console.log('somevariable of closure %s is: %s',
        closure, somevariable);
    }
  }
}

closure_one = example('one');
closure_two = example('two');

closure_one.log();
closure_two.log();
closure_one.change_to('some new value');
closure_one.log();
closure_two.log();

Salida

somevariable of closure one is: unchanged
somevariable of closure two is: unchanged
somevariable of closure one is: some new value
somevariable of closure two is: unchanged

Escribí un post en el blog hace un tiempo explicar los cierres.Aquí es lo que he dicho acerca de los cierres en los términos de por qué te gustaría uno.

Los cierres son una forma de que una función han persistente, variables privadas - es decir, variables que sólo uno función de conocimiento, donde se puede mantener un seguimiento de la información de tiempos anteriores que se ejecuta.

En ese sentido, se deja una ley de la función un poco como un objeto privado con atributos.

Post completo:

Entonces, ¿qué son estos cierre thingys?

Los cierres son simples:

En el siguiente ejemplo simple cubre todos los puntos principales de JavaScript cierres.*  

Aquí es una fábrica que produce las calculadoras que pueden sumar y multiplicar:

function make_calculator() {
  var n = 0; // this calculator stores a single number n
  return {
    add: function(a) {
      n += a;
      return n;
    },
    multiply: function(a) {
      n *= a;
      return n;
    }
  };
}

first_calculator = make_calculator();
second_calculator = make_calculator();

first_calculator.add(3); // returns 3
second_calculator.add(400); // returns 400

first_calculator.multiply(11); // returns 33
second_calculator.multiply(10); // returns 4000

El punto clave: Cada llamada a make_calculator crea una nueva variable local n, que sigue siendo utilizable por que la calculadora add y multiply funciones mucho tiempo después de make_calculator devuelve.

Si usted está familiarizado con los marcos de pila, estas calculadoras parecer extraño:¿Cómo pueden mantener el acceso a n después de make_calculator devuelve?La respuesta es imaginar que JavaScript no uso "marcos de pila", pero en su lugar utiliza el "montón de marcos", que pueden persistir después de la llamada a la función que les hizo devuelve.

Interior en funciones como add y multiply, que el acceso a las variables declaradas en una función externa**, son llamados cierres.

Eso es prácticamente todo lo que hay a los cierres.



* Por ejemplo, cubre todos los puntos de la "Cierres para Dummies" artículo determinado en otra respuesta, excepto el ejemplo 6, que simplemente muestra que las variables pueden ser utilizados antes de que se haya declarado, una bonita hecho saber, pero completamente ajena a los cierres.También cubre todos los puntos en el aceptó responder, excepto por los puntos (1) que las funciones de copiar sus argumentos en variables locales (el nombre de los argumentos de la función), y (2) que copiar números crea un nuevo número, pero la copia de un objeto de referencia le da otra referencia al mismo objeto.Estas también son buenas para saber, pero de nuevo completamente ajenos a los cierres.También es muy similar a la del ejemplo en esta respuesta pero un poco más corto y menos abstracta.No cubre el punto de esta respuesta o este comentario, que es el JavaScript que hace que sea difícil para tapar el actual el valor de una variable de bucle en su interior función:El "enchufar" el paso sólo se puede hacer con una función auxiliar que encierra su interior y función se invoca en cada iteración del bucle.(Estrictamente hablando, el interior de la función de los accesos de la función auxiliar de la copia de la variable, en lugar de tener nada enchufado.) De nuevo, muy útil a la hora de crear los cierres, pero no parte de lo que un cierre es o cómo funciona.Existe mayor confusión debido a los cierres de trabajo de manera diferente en los lenguajes funcionales como ML, donde las variables están obligados a valores en lugar de espacio de almacenamiento, proporcionando un flujo constante de personas que entienden los cierres de una manera (es decir, la "conectar") que es simplemente incorrecta para JavaScript, donde las variables son siempre obligado a espacio de almacenamiento, y nunca a los valores.

** Cualquier externa de la función, si varios son anidados, o incluso en el contexto global, como esta respuesta señala claramente.

Cómo me gustaría explicarlo a un niño de seis años:

Usted sabe cómo los adultos pueden ser propietario de una casa, y llaman a casa?Cuando una madre tiene un hijo, el niño realmente no poseer nada, ¿verdad?Pero sus padres dueño de una casa, así que cada vez que alguien le pregunta al niño "¿Dónde está tu casa?", él/ella puede responder a "la casa!", y el punto a la casa de sus padres.Un "Cierre" es la capacidad del niño para siempre (incluso si es en el extranjero) ser capaz de decir que tiene un hogar, a pesar de que es realmente el padre de la dueña de la casa.

Puede usted explicar los cierres para un niño de 5 años de edad?*

Todavía creo Google explicación funciona muy bien y es concisa:

/*
*    When a function is defined in another function and it
*    has access to the outer function's context even after
*    the outer function returns.
*
* An important concept to learn in JavaScript.
*/

function outerFunction(someNum) {
    var someString = 'Hey!';
    var content = document.getElementById('content');
    function innerFunction() {
        content.innerHTML = someNum + ': ' + someString;
        content = null; // Internet Explorer memory leak for DOM reference
    }
    innerFunction();
}

outerFunction(1);​

Proof that this example creates a closure even if the inner function doesn

*Un C# pregunta

Me tienden a aprender mejor por las BUENAS/MALAS comparaciones.Me gusta ver el código de trabajo seguido por los no-código de trabajo que es probable que alguien que se encuentre.Pongo juntos un jsFiddle que hace una comparación y trata de que se reducen las diferencias a la más simple de las explicaciones que se me podía venir.

Cierres de hecho a la derecha:

console.log('CLOSURES DONE RIGHT');

var arr = [];

function createClosure(n) {
    return function () {
        return 'n = ' + n;
    }
}

for (var index = 0; index < 10; index++) {
    arr[index] = createClosure(index);
}

for (var index in arr) {
    console.log(arr[index]());
}
  • En el código anterior createClosure(n) se invoca en cada iteración del bucle.Tenga en cuenta que puse el nombre de la variable n a destacar que es una nuevo variable creada en un nuevo ámbito de la función y no es la misma variable como index que está enlazado el alcance externo.

  • Esto crea un nuevo ámbito y n está enlazado a ese ámbito;esto significa que tenemos 10 ámbitos independientes, uno para cada iteración.

  • createClosure(n) devuelve una función que devuelve el n dentro de ese ámbito.

  • Dentro de cada ámbito n es obligado para cualquier valor que tenía cuando createClosure(n) fue invocada de modo que la función anidada que obtiene regresó siempre devolverá el valor de n que tenía cuando createClosure(n) fue invocada.

Cierres hecho mal:

console.log('CLOSURES DONE WRONG');

function createClosureArray() {
    var badArr = [];

    for (var index = 0; index < 10; index++) {
        badArr[index] = function () {
            return 'n = ' + index;
        };
    }
    return badArr;
}

var badArr = createClosureArray();

for (var index in badArr) {
    console.log(badArr[index]());
}
  • En el código anterior que el ciclo se ha movido dentro de la createClosureArray() la función y la función ahora sólo devuelve el completada la matriz, que a primera vista parece más intuitivo.

  • Lo que puede no ser evidente es que desde createClosureArray() sólo se invoca una vez sólo un ámbito creado para esta función en lugar de uno por cada iteración del bucle.

  • Dentro de esta función una variable llamada index está definido.El bucle se ejecuta y añade funciones a la matriz que volver index.Tenga en cuenta que index se define dentro de la createClosureArray la función de la que sólo se invoca una sola vez.

  • Porque no fue sólo un ámbito dentro de la createClosureArray() la función, index sólo está obligado a un valor dentro de ese ámbito.En otras palabras, cada vez que el bucle se cambia el valor de index, la cambia para que todo lo que hace referencia a que dentro de ese ámbito.

  • Todas las funciones de agregado a la matriz de devolución de la MISMA index variable desde el ámbito primario donde se definió en lugar de 10 diferentes de 10 diferentes ámbitos como en el primer ejemplo.El resultado final es que todos los 10 de retorno de funciones de la misma variable desde el mismo ámbito.

  • Después de que el bucle termine y index fue hecho de ser modificado el valor final fue de 10, por lo tanto, cada función se agrega a la matriz devuelve el valor de la sola index la variable de la que ahora se establece en 10.

Resultado

CIERRES DE HECHO A LA DERECHA
n = 0
n = 1
n = 2
n = 3
n = 4
n = 5
n = 6
n = 7
n = 8
n = 9

CIERRES HECHO MAL
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10

Wikipedia en cierres:

En ciencias de la computación, un cierre a una función, junto con un entorno de referencia para los nombres no locales (variables libres) de esa función.

Técnicamente, en JavaScript, cada función es un cierre.Siempre tiene un acceso a las variables definidas en el ámbito que lo rodea.

Desde alcance de la definición de la construcción en JavaScript es una función, no un bloque de código como en muchos otros idiomas, lo que se suele decir por cierre en JavaScript es un la función de trabajar con variables no locales definidas en los ya ejecutados de los alrededores de la función.

Los cierres se utiliza a menudo para crear funciones con algunos de los secretos de datos privados (pero no siempre es el caso).

var db = (function() {
    // Create a hidden object, which will hold the data
    // it's inaccessible from the outside.
    var data = {};

    // Make a function, which will provide some access to the data.
    return function(key, val) {
        if (val === undefined) { return data[key] } // Get
        else { return data[key] = val } // Set
    }
    // We are calling the anonymous surrounding function,
    // returning the above inner function, which is a closure.
})();

db('x')    // -> undefined
db('x', 1) // Set x to 1
db('x')    // -> 1
// It's impossible to access the data object itself.
// We are able to get or set individual it.

ems

El ejemplo anterior es el uso de una función anónima, la cual se ejecuta una vez.Pero no tiene que ser.Tambien puede ser llamado (por ejemplo, mkdb) y ejecutado más tarde, la generación de una función de base de datos cada vez que se invoca.Cada función generada tendrá su propia base de datos oculta objeto.Otro ejemplo de uso de cierres es cuando no estamos de retorno de una función, sino un objeto que contiene varias funciones para diferentes propósitos, cada uno de esos función de tener acceso a los mismos datos.

Armé un sistema interactivo de JavaScript tutorial para explicar cómo los cierres de trabajo.¿Qué es un Cierre?

He aquí uno de los ejemplos:

var create = function (x) {
    var f = function () {
        return x; // We can refer to x here!
    };
    return f;
};
// 'create' takes one argument, creates a function

var g = create(42);
// g is a function that takes no arguments now

var y = g();
// y is 42 here

Los niños van a recordar siempre los secretos que han compartido con sus padres, incluso después de que sus padres son ha ido.Esto es lo que los cierres son para las funciones.

Los secretos de las funciones de JavaScript son las variables privadas

var parent = function() {
 var name = "Mary"; // secret
}

Cada vez que llama, local de la variable "nombre" es creado y dado el nombre de "María".Y cada vez que sale de la función de la variable se pierde y el nombre es olvidado.

Como es de suponer, debido a que las variables se vuelve a crear cada vez que se llama a la función, y nadie va a saber de ellos, debe haber un lugar secreto donde están almacenados.Podría ser llamado Cámara de los Secretos o pila o de ámbito local pero realmente no importa.Sabemos que están ahí, en algún lugar, escondido en la memoria.

Pero, en JavaScript no es esta cosa muy especial que las funciones que se crean dentro de otras funciones, también pueden conocer las variables locales de sus padres y a mantenerlos en el tiempo que vivan.

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    // I can also see that "name" is "Mary"
  }
}

Así que, mientras estamos en el padre -función, puede crear una o más funciones de las que comparten el secreto de las variables desde el lugar secreto.

Pero lo triste es que, si el hijo es también una variable privada de su función principal, también mueren cuando el padre termina, y los secretos que iba a morir con ellos.

Así que a vivir, el niño tiene que salir antes de que sea demasiado tarde

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    return "My name is " + childName  +", child of " + name; 
  }
  return child; // child leaves the parent ->
}
var child = parent(); // < - and here it is outside 

Y ahora, incluso a pesar de que María es "ya no se está ejecutando", la memoria de ella no está perdido y de que su hijo siempre recordar su nombre y otros secretos que compartieron durante su tiempo juntos.

Por lo tanto, si usted llama el niño de "Alice", ella le responde

child("Alice") => "My name is Alice, child of Mary"

Eso es todo lo que hay que decir.

Yo no entiendo por qué las respuestas son tan complejo.

Aquí es un cierre:

var a = 42;

function b() { return a; }

Sí.Es probable que el uso que muchas veces en un día.


No hay ninguna razón para creer que los cierres son de un diseño complejo hack para abordar problemas específicos.No, los cierres son sólo acerca del uso de una variable que viene de un ámbito superior desde la perspectiva de donde la función se declara (no ejecutar).

Ahora lo que permite usted puede ser más espectacular, ver otras respuestas.

Ejemplo para el primer punto por dlaliberte:

Un cierre que no sólo se crea cuando regrese interior de la función.De hecho, la que encierra la función no es necesario volver a todos.Usted puede en lugar de asignar su interior la función a una variable en un alcance externo, o pasar como argumento a otra función que le pueda ser utilizado de inmediato.Por lo tanto, el cierre de la envolvente de la función probablemente ya existe en el momento en que encierra la función fue llamada desde cualquier interior función tiene acceso a ella tan pronto como se llama.

var i;
function foo(x) {
    var tmp = 3;
    i = function (y) {
        console.log(x + y + (++tmp));
    }
}
foo(2);
i(3);

Un cierre es donde un interno de la función tiene acceso a las variables en su exterior la función.Ese es probablemente el más simple de una línea de explicación que puede tener para los cierres.

Sé que hay un montón de soluciones ya, pero supongo que este pequeño y sencillo script puede ser útil para demostrar el concepto:

// makeSequencer will return a "sequencer" function
var makeSequencer = function() {
    var _count = 0; // not accessible outside this function
    var sequencer = function () {
        return _count++;
    }
    return sequencer;
}

var fnext = makeSequencer();
var v0 = fnext();     // v0 = 0;
var v1 = fnext();     // v1 = 1;
var vz = fnext._count // vz = undefined

Estás teniendo un sueño y te invitamos a Dan.Informar Dan para llevar un control de XBox.

Dan invita a Pablo.Dan Pablo pide a traer un controlador.Cuántos controladores fueron llevados a la fiesta?

function sleepOver(howManyControllersToBring) {

    var numberOfDansControllers = howManyControllersToBring;

    return function danInvitedPaul(numberOfPaulsControllers) {
        var totalControllers = numberOfDansControllers + numberOfPaulsControllers;
        return totalControllers;
    }
}

var howManyControllersToBring = 1;

var inviteDan = sleepOver(howManyControllersToBring);

// The only reason Paul was invited is because Dan was invited. 
// So we set Paul's invitation = Dan's invitation.

var danInvitedPaul = inviteDan(howManyControllersToBring);

alert("There were " + danInvitedPaul + " controllers brought to the party.");

Las funciones de JavaScript puede tener acceso a su:

  1. Argumentos
  2. Locales (es decir, sus variables locales y las funciones locales)
  3. Medio ambiente, que incluye:
    • globales, incluyendo el DOM
    • nada en el exterior de las funciones

Si una función de los accesos de su entorno, entonces la función es un cierre.

Tenga en cuenta que exterior funciones no son necesarios, aunque no ofrecen beneficios no quiero discutir aquí.Por el acceso a los datos de su entorno, en un cierre que mantiene los datos en vivo.En el subcase de exterior/interior de funciones, una externa de la función puede crear datos locales y, finalmente, a la salida, y sin embargo, si cualquier interior de la función(s) de sobrevivir después de que el exterior de la función de las salidas, luego el interior de la función(s) de mantener el exterior de la función de datos locales vivo.

Ejemplo de un cierre que utiliza el medio ambiente mundial:

Imagina que el Desbordamiento de la Pila de Voto y Voto hacia Abajo el botón de eventos se implementan como los cierres, voteUp_click y voteDown_click, que tienen acceso a las variables externas isVotedUp y isVotedDown, que se definen a nivel mundial.(Para simplificar, me refiero a la Pregunta de StackOverflow botones de Votación, no la matriz de Respuesta botones de Votación.)

Cuando el usuario hace clic en el VoteUp botón, el voteUp_click función comprueba si isVotedDown == true para determinar si votar a favor o simplemente cancelar un voto.Función voteUp_click es un cierre porque es acceder a su entorno.

var isVotedUp = false;
var isVotedDown = false;

function voteUp_click() {
  if (isVotedUp)
    return;
  else if (isVotedDown)
    SetDownVote(false);
  else
    SetUpVote(true);
}

function voteDown_click() {
  if (isVotedDown)
    return;
  else if (isVotedUp)
    SetUpVote(false);
  else
    SetDownVote(true);
}

function SetUpVote(status) {
  isVotedUp = status;
  // Do some CSS stuff to Vote-Up button
}

function SetDownVote(status) {
  isVotedDown = status;
  // Do some CSS stuff to Vote-Down button
}

Estas cuatro funciones son los cierres, ya que todos acceder a su entorno.

El autor de Cierres ha explicado cierres bastante bien, explicando la razón por la que necesitamos y también explicando LexicalEnvironment que es necesario para la comprensión de los cierres.
Aquí está el resumen:

¿Qué pasa si una variable se accede, pero no es local?Como aquí:

Enter image description here

En este caso, el intérprete se encuentra la variable en el exterior LexicalEnvironment objeto.

El proceso consta de dos pasos:

  1. En primer lugar, cuando una función f se crea, no se crea en un vacío espacio.Hay una corriente LexicalEnvironment objeto.En el caso arriba, la ventana (una es indefinido en el tiempo de la función la creación).

Enter image description here

Cuando una función se crea, se obtiene de una ocultos de la propiedad, denominado [[Ámbito de aplicación]], que hace referencia a la actual LexicalEnvironment.

Enter image description here

Si una variable es leer, pero no puede ser encontrado en cualquier lugar, se genera un error.

Funciones anidadas

Las funciones pueden ser anidados uno dentro de otro, formando una cadena de LexicalEnvironments que también puede ser llamado un ámbito de la cadena.

Enter image description here

Así, la función g tiene acceso a la g, a y f.

Cierres

Una función anidada puede seguir viviendo después de que el exterior de la función ha terminado:

Enter image description here

El marcado de LexicalEnvironments:

Enter image description here

Como vemos, this.say es una propiedad en el objeto de usuario, por lo que sigue viva después de que el Usuario ha completado.

Y si usted recuerda, cuando this.say se crea, (ya que cada función) obtiene una referencia interna this.say.[[Scope]] el actual LexicalEnvironment.Así, el LexicalEnvironment de la actual ejecución por parte del Usuario permanece en la memoria.Todas las variables de Usuario también son sus propiedades, por lo que son también cuidadosamente mantenido, no chatarra como de costumbre.

El punto es asegurarse de que si el interior de la función quiere acceder a una variable externa en el futuro, es capaz de hacerlo.

Para resumir:

  1. El interior de la función mantiene una referencia para el exterior LexicalEnvironment.
  2. El interior de la función puede acceder a las variables de él cualquier momento, incluso si el exterior de la función termine.
  3. El navegador guarda el LexicalEnvironment y de todas sus propiedades (variables) en la memoria hasta que haya una interna, la función que hace referencia a ella.

Esto se llama un cierre.

Como padre de un niño de 6 años, en la actualidad la enseñanza de los niños pequeños (y un relativo novato a la codificación con la no formal, la educación para correcciones será necesario), creo que la lección quedaría mejor a través de las manos-en el juego.Si la edad de 6 años está listo para entender lo que es un cierre, entonces ellos tienen la edad suficiente para tener un ir a sí mismos.Te sugiero que pegar el código de jsfiddle.net explicando un poco, y dejando a inventar una única canción.El texto explicativo a continuación es probablemente más apropiado para un hijo de 10 años.

function sing(person) {

    var firstPart = "There was " + person + " who swallowed ";

    var fly = function() {
        var creature = "a fly";
        var result = "Perhaps she'll die";
        alert(firstPart + creature + "\n" + result);
    };

    var spider = function() {
        var creature = "a spider";
        var result = "that wiggled and jiggled and tickled inside her";
        alert(firstPart + creature + "\n" + result);
    };

    var bird = function() {
        var creature = "a bird";
        var result = "How absurd!";
        alert(firstPart + creature + "\n" + result);
    };

    var cat = function() {
        var creature = "a cat";
        var result = "Imagine That!";
        alert(firstPart + creature + "\n" + result);
    };

    fly();
    spider();
    bird();
    cat();
}

var person="an old lady";

sing(person);

INSTRUCCIONES

DATOS:De datos es una colección de datos.Pueden ser números, palabras, mediciones, observaciones o incluso sólo las descripciones de las cosas.No se puede tocar, oler o saborear.Usted puede escribir, hablar y escuchar.Usted puede usarlo para crear el tacto el olfato y el gusto de usar un ordenador.Puede ser útil por un equipo con código.

CÓDIGO:Todo lo escrito anteriormente se llama código.Está escrito en JavaScript.

JAVASCRIPT:JavaScript es un lenguaje.Como el inglés o el francés o el Chino son los idiomas.Hay un montón de idiomas que se entiende por las computadoras y otros medios electrónicos procesadores.Para JavaScript para ser entendido por un equipo que necesita un intérprete.Imagínese si un profesor que sólo habla ruso viene a enseñar a su clase en la escuela.Cuando el profesor dice "все садятся", la clase no comprende.Pero por suerte tienes un ruso alumno en su clase que le dice a todos que esto significa que "todo el mundo siéntate" - para que todos lo hacen.La clase es como un equipo de rusia y la pupila es el intérprete.Para JavaScript, el más común intérprete se llama un navegador.

NAVEGADOR:Cuando se conecta a Internet en un ordenador, tablet o teléfono para que visite un sitio web, debe utilizar un navegador.Ejemplos usted puede saber que son Internet Explorer, Chrome, Firefox y Safari.El navegador puede entender JavaScript y decirle a la computadora lo que debe hacer.El JavaScript instrucciones se llaman funciones.

FUNCIÓN:Una función en JavaScript es como una fábrica.Podría ser una pequeña fábrica con una sola máquina en el interior.O puede contener muchas otras fábricas pequeñas, cada una con muchas máquinas, realizando diferentes trabajos.En la vida real fábrica de ropa podría tener montones de tela y bobinas de hilo que pasa en y camisetas y los pantalones vaqueros de salir.Nuestro código JavaScript de la fábrica sólo de procesos de datos, no puede coser, taladre un agujero o fundir el metal.En nuestro código JavaScript datos de fábrica va en datos y sale.

Todos los datos de este material suena un poco aburrido, pero es realmente muy cool;podemos tener una función que le dice a un robot qué hacer para la cena.Digamos que yo invito a usted y a su amigo a mi casa.Te gustan las piernas de pollo mejor, me gustan las salchichas, su amigo siempre quiere lo que quiere y mi amigo no comer carne.

No tengo tiempo para ir de compras, por lo que la función necesita saber lo que tenemos en la nevera para tomar decisiones.Cada ingrediente tiene un diferente tiempo de cocción y queremos que todo ser servido caliente por el robot al mismo tiempo.Tenemos que proporcionar la función con los datos acerca de lo que nos gusta, la función no se puede "hablar" a la nevera, y la función no se puede controlar el robot.

Una función que normalmente tiene un nombre, entre paréntesis y llaves.Como este:

function cookMeal() {  /*  STUFF INSIDE THE FUNCTION  */  }

Tenga en cuenta que /*...*/ y // código de detención de ser leído por el navegador.

NOMBRE:Usted puede llamar a una función sólo acerca de cualquier palabra que desee.El ejemplo "cookMeal" es típico en unir dos palabras, y dando a la segunda una letra mayúscula al principio - pero esto no es necesario.No puede tener un espacio en él, y no puede ser un número en su propio.

PARÉNTESIS:"Paréntesis" o () son la carta de cuadro en la función de JavaScript de la fábrica de la puerta o un apartado de correos en la calle para el envío de paquetes de información a la fábrica.A veces el buzón podría estar marcada por ejemplo cookMeal(you, me, yourFriend, myFriend, fridge, dinnerTime), en el que caso de que usted sabe lo que los datos que tiene que dar.

LLAVES:"Llaves" que este aspecto {} son los vidrios polarizados de fábrica.Desde el interior de la fábrica se puede ver, pero desde fuera no se puede ver en.

LA LARGA CÓDIGO DEL EJEMPLO ANTERIOR

Nuestro código comienza con la palabra la función, así sabemos que es uno!A continuación, el nombre de la función cantar - ese es mi propia descripción de lo que la función se acerca.A continuación, entre paréntesis ().Los paréntesis siempre están ahí para una función.A veces están vacíos, y a veces tienen algo en.Este tiene la palabra en: (person).Después de esto hay un soporte como este { .Esto marca el inicio de la función cantar().Tiene un socio que marca el final de cantar() como este }

function sing(person) {  /* STUFF INSIDE THE FUNCTION */  }

Por lo que esta función podría tener algo que ver con el canto, y podría necesitar algunos datos acerca de una persona.Tiene instrucciones en su interior para hacer algo con esos datos.

Ahora, después de la función cantar(), cerca del final de la código de la línea

var person="an old lady";

VARIABLE:Las letras var stand de "variable".Una variable es como un sobre.En el exterior de este sobre está marcado con una "persona".En el interior contiene una hoja de papel con la información de nuestra función de las necesidades, algunas de las letras y los espacios se unieron como un trozo de cuerda (se llama una cadena) que hacen que una frase de la lectura de "una vieja dama".Nuestros sobres podría contener otro tipo de cosas como los números (llamados enteros), instrucciones (llamadas a funciones), listas (llamado matrices).Debido a que esta variable se escribe fuera de todas las llaves {}, y porque se puede ver a través de los vidrios polarizados cuando usted se encuentra dentro de las llaves, esta variable puede ser visto desde cualquier lugar en el código.Llamamos a esto una "variable global'.

VARIABLE GLOBAL: persona es una variable global, lo que significa que si usted cambia su valor a partir de "una vieja señora" a "un joven", el persona va a seguir siendo un hombre joven, hasta que se decide a cambiar de nuevo y que cualquier otra función en el código podemos ver que es un hombre joven.Pulse el F12 botón o buscar en las Opciones de configuración para abrir la consola para desarrolladores del navegador y el tipo de "persona" para ver lo que este valor es.Tipo de person="a young man" cambiar y, a continuación, escriba "persona" de nuevo para ver que ha cambiado.

Después de esto tenemos la línea de

sing(person);

Esta línea es la llamada a la función, como si estuviera llamando a un perro

"Vienen en cantar, Ven y consigue persona!"

Cuando el navegador ha cargado el código JavaScript de un alcanzada esta línea, va a empezar la función.Puedo poner la línea en el final para asegurarse de que el navegador tiene toda la información que necesita para ejecutarlo.

Funciones definir acciones - la función principal es sobre el canto.Contiene una variable llamada firstPart que se aplica el canto acerca de la persona a la que se aplica a cada uno de los versos de la canción:"Hubo" + persona + "que se ingiere".Si el tipo de firstPart en la consola, usted no obtendrá una respuesta debido a que la variable es encerrado en una función - el navegador no puede ver el interior de los vidrios polarizados de las llaves.

CIERRES:Los cierres son de la más pequeña de las funciones que están dentro de la gran cantar() la función.Las fábricas pequeñas en el interior de la gran fábrica.Cada uno de ellos tiene sus propias llaves, lo que significa que las variables dentro de ellos no pueden ser vistos desde el exterior.Es por eso que los nombres de las variables (la criatura y resultado) puede ser repetido en los cierres, pero con diferentes valores.Si usted escriba los nombres de las variables en la ventana de la consola, no obtendrá su valor porque está oculto por dos capas de vidrios polarizados.

Los cierres todos sabemos lo que el cantar() de la función en la variable llamada firstPart es decir, porque se puede ver a partir de sus vidrios polarizados.

Después de los cierres vienen de las líneas

fly();
spider();
bird();
cat();

El cantar() la función se llame a cada una de estas funciones en el orden en que se dan.A continuación, el cantar() de la función en la que se hará el trabajo.

Bueno, hablando con un niño de 6 años de edad, hijo, yo posiblemente usar las siguientes asociaciones.

Imagine que usted está jugando con sus pequeños hermanos y hermanas en toda la casa, y usted se está moviendo a su alrededor con sus juguetes y llevó a algunos de ellos a su hermano de la habitación.Después de un tiempo su hermano volvió de la escuela y se fue a su habitación, y él encerrado en su interior, de modo que ahora no podían acceder a los juguetes a la izquierda hay más de una manera directa.Pero usted podría golpear la puerta y pregunte a su hermano para que los juguetes.Esto se llama juguete cierre;su hermano hizo por ti, y ahora está en el exterior alcance.

Comparar con la situación de que cuando una puerta estaba cerrada por el proyecto y nadie en el interior (función general de ejecución) y, a continuación, algunos de bomberos local ocurrir y quemar la habitación (recolector de basura:D) y, a continuación, una nueva habitación era construir y ahora puede dejar otro de los juguetes que hay (la nueva función de instancia), pero nunca llegar a la misma juguetes que estaban a la izquierda en la primera de la sala de instancia.

Para un avanzado niño yo pondría algo como la siguiente.No es perfecto, pero hace que usted siente acerca de lo que es:

function playingInBrothersRoom (withToys) {
  // We closure toys which we played in the brother's room. When he come back and lock the door
  // your brother is supposed to be into the outer [[scope]] object now. Thanks god you could communicate with him.
  var closureToys = withToys || [],
      returnToy, countIt, toy; // Just another closure helpers, for brother's inner use.

  var brotherGivesToyBack = function (toy) {
    // New request. There is not yet closureToys on brother's hand yet. Give him a time.
    returnToy = null;
    if (toy && closureToys.length > 0) { // If we ask for a specific toy, the brother is going to search for it.

      for ( countIt = closureToys.length; countIt; countIt--) {
        if (closureToys[countIt - 1] == toy) {
          returnToy = 'Take your ' + closureToys.splice(countIt - 1, 1) + ', little boy!';
          break;
        }
      }
      returnToy = returnToy || 'Hey, I could not find any ' + toy + ' here. Look for it in another room.';
    }
    else if (closureToys.length > 0) { // Otherwise, just give back everything he has in the room.
      returnToy = 'Behold! ' + closureToys.join(', ') + '.';
      closureToys = [];
    }
    else {
      returnToy = 'Hey, lil shrimp, I gave you everything!';
    }
    console.log(returnToy);
  }
  return brotherGivesToyBack;
}
// You are playing in the house, including the brother's room.
var toys = ['teddybear', 'car', 'jumpingrope'],
    askBrotherForClosuredToy = playingInBrothersRoom(toys);

// The door is locked, and the brother came from the school. You could not cheat and take it out directly.
console.log(askBrotherForClosuredToy.closureToys); // Undefined

// But you could ask your brother politely, to give it back.
askBrotherForClosuredToy('teddybear'); // Hooray, here it is, teddybear
askBrotherForClosuredToy('ball'); // The brother would not be able to find it.
askBrotherForClosuredToy(); // The brother gives you all the rest
askBrotherForClosuredToy(); // Nothing left in there

Como se puede ver, los juguetes se quedan en la sala son todavía accesibles a través del hermano y no importa si la habitación está bloqueado.Aquí es un jsbin a jugar con ella.

Una respuesta para un periodo de seis años (suponiendo que él sabe qué función y qué es una variable, y qué datos):

Las funciones pueden devolver datos.Un tipo de datos que usted puede volver de una función es otra función.Cuando esa nueva función obtiene regresó, todas las variables y argumentos que se usan en la función que la ha creado no desaparecen.En su lugar, que los padres de la función "cierra". En otras palabras, nada puede ver dentro de ella y ver las variables que se usa, excepto para la función que debe devolver.Que la nueva función tiene una habilidad especial para mirar hacia atrás dentro de la función que la ha creado y ver los datos dentro de ella.

function the_closure() {
  var x = 4;
  return function () {
    return x; // Here, we look back inside the_closure for the value of x
  }
}

var myFn = the_closure();
myFn(); //=> 4

Otra manera muy sencilla de explicarlo es en términos de alcance:

Cualquier momento de crear un ámbito más reducido dentro de un ámbito mayor, el menor alcance siempre será capaz de ver lo que es en el ámbito mayor.

Una función en JavaScript no es sólo una referencia a un conjunto de instrucciones (como en el lenguaje C), pero también incluye una ocultos estructura de datos que se compone de referencias a todos los no locales las variables que utiliza (capturado variables).Estas dos piezas se llama a las funciones de cierre.Cada función en JavaScript puede ser considerado como un cierre.

Los cierres son funciones de estado.Es algo similar a "este", en el sentido de que "esto" también proporciona el estado para una función, pero la función de "y" son objetos separados ("esto" es sólo una fantasía parámetro, y la única manera de enlazar de manera permanente a una función es crear un cierre).Mientras que el "este" y la función siempre de vivir separado, una función no puede ser separado de su cierre y el lenguaje no proporciona medios para acceder capturado variables.

Porque todas estas variables externas que se hace referencia por un léxicamente función anidada en realidad son variables locales en la cadena de su léxico, adjuntando funciones (variables globales se puede asumir que las variables locales de una raíz de la función), y en cada ejecución de una función crea nuevas instancias de sus variables locales, se deduce que cada ejecución de una función que devuelve (o de otra forma transferir a cabo, tales como el registro como una devolución de llamada) una función anidada crea un nuevo cierre (con su propio potencialmente conjunto único de referencia no local de las variables que representan su contexto de ejecución).

También, se debe entender que las variables locales en JavaScript, creado en el marco de pila, pero en el montón y destruye sólo cuando nadie está haciendo referencia a ellos.Cuando una función devuelve, las referencias a sus variables locales son disminuye, pero aún así pueden ser no nulo si durante la ejecución actual se convirtieron en parte de un cierre y todavía se hace referencia por su léxicamente funciones anidadas (lo cual sólo puede suceder si las referencias a estas funciones anidadas fueron devueltos o transferidos a código externo).

Un ejemplo:

function foo (initValue) {
   //This variable is not destroyed when the foo function exits.
   //It is 'captured' by the two nested functions returned below.
   var value = initValue;

   //Note that the two returned functions are created right now.
   //If the foo function is called again, it will return
   //new functions referencing a different 'value' variable.
   return {
       getValue: function () { return value; },
       setValue: function (newValue) { value = newValue; }
   }
}

function bar () {
    //foo sets its local variable 'value' to 5 and returns an object with
    //two functions still referencing that local variable
    var obj = foo(5);

    //Extracting functions just to show that no 'this' is involved here
    var getValue = obj.getValue;
    var setValue = obj.setValue;

    alert(getValue()); //Displays 5
    setValue(10);
    alert(getValue()); //Displays 10

    //At this point getValue and setValue functions are destroyed
    //(in reality they are destroyed at the next iteration of the garbage collector).
    //The local variable 'value' in the foo is no longer referenced by
    //anything and is destroyed too.
}

bar();

Tal vez un poco más allá de todos, pero el más precoz de los niños de seis años, pero un par de ejemplos, que ayudaron a que el concepto de cierre en JavaScript haga clic en para mí.

Un cierre es una función que tiene acceso a otra función del ámbito de sus variables y funciones).La manera más fácil para crear un cierre con una función dentro de una función;la razón es que en JavaScript una función siempre tiene acceso a su contengan función de su ámbito.

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        alert(outerVar);
    }
    
    innerFunction();
}

outerFunction();

ALERTA:mono

En el ejemplo anterior, outerFunction se llama, que a su vez llama a innerFunction.Nota cómo outerVar está disponible para innerFunction, evidenciado por su correctamente alerta el valor de outerVar.

Ahora considere la siguiente:

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        return outerVar;
    }
    
    return innerFunction;
}

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

ALERTA:mono

referenceToInnerFunction se establece en outerFunction(), que simplemente devuelve una referencia a innerFunction.Cuando referenceToInnerFunction se llama, devuelve outerVar.De nuevo, como en el anterior, esto demuestra que innerFunction tiene acceso a outerVar, una variable de outerFunction.Por otra parte, es interesante notar que conserva este acceso, incluso después de outerFunction ha terminado de ejecutarse.

Y aquí es donde las cosas se ponen realmente interesantes.Si nos fuera a deshacerse de outerFunction, dicen que establece a null, se podría pensar que referenceToInnerFunction perdería su acceso al valor de outerVar.Pero este no es el caso.

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        return outerVar;
    }
    
    return innerFunction;
}

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

outerFunction = null;
alert(referenceToInnerFunction());

ALERTA:mono ALERTA:mono

Pero, ¿cómo es esto así?¿Cómo puede referenceToInnerFunction todavía saber el valor de outerVar ahora que outerFunction ha sido establecido en null?

La razón por la que referenceToInnerFunction todavía puede tener acceso al valor de outerVar es porque cuando el cierre fue creado por la colocación de innerFunction dentro de outerFunction, innerFunction añadido una referencia a outerFunction del ámbito de sus variables y funciones) a su ámbito de aplicación de la cadena.Lo que esto significa es que innerFunction tiene un puntero o referencia a todos outerFunction de variables, incluyendo la outerVar.Así que incluso cuando outerFunction ha terminado de ejecutarse, o incluso si se elimina o se establece en null, las variables en su ámbito de aplicación, como outerVar, quédate en la memoria gracias a la excelente referencia a ellos en la parte de la innerFunction que haya sido devuelto a referenceToInnerFunction.Realmente liberación outerVar y el resto de outerFunction las variables de la memoria tendría que deshacerse de este destacado referencia a ellos, dicen que por la configuración de referenceToInnerFunction a null así.

//////////

Otras dos cosas sobre los cierres a la nota.En primer lugar, el cierre siempre tendrá acceso a los últimos valores de su que contiene la función.

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        alert(outerVar);
    }
    
    outerVar = "gorilla";

    innerFunction();
}

outerFunction();

ALERTA:gorila

En segundo lugar, cuando se crea una cerradura, se conserva una referencia a todos los de su adjuntando función de las variables y funciones;no elegir.Y sino es así, los cierres deben ser usadas con moderación, o al menos cuidadosamente, ya que pueden ser intensivas de memoria;una gran cantidad de variables que pueden ser guardados en la memoria mucho después de que contiene la función ha terminado de ejecutarse.

Yo simplemente le apunten a la Mozilla Cierres la página.Es el mejor, la mayoría de los conciso y simple explicación de cierre de conceptos básicos y de uso práctico que he encontrado.Es altamente recomendable para cualquier persona en el aprendizaje de JavaScript.

Y sí, yo incluso recomendaría a un niño de 6 años -- si a los 6 años de edad, está aprendiendo acerca de los cierres, entonces es lógico que estén listos para comprender la conciso y simple explicación prevé en el artículo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top