tutorial funciona español ejemplos definicion curso como caracteristicas javascript closures terminology

funciona - javascript pdf



¿Cuál es un uso práctico para un cierre en JavaScript? (20)

Gran parte del código que escribimos en JavaScript de front-end está basado en eventos: definimos algún comportamiento, luego lo adjuntamos a un evento que es activado por el usuario (como un clic o una pulsación de tecla). Nuestro código generalmente se adjunta como devolución de llamada: una función única que se ejecuta en respuesta al evento. size12, size14 y size16 ahora son funciones que cambiarán el tamaño del texto del cuerpo a 12, 14 y 16 píxeles, respectivamente. Podemos adjuntarlos a los botones (en este caso enlaces) de la siguiente manera:

function makeSizer(size) { return function() { document.body.style.fontSize = size + ''px''; }; } var size12 = makeSizer(12); var size14 = makeSizer(14); var size16 = makeSizer(16); document.getElementById(''size-12'').onclick = size12; document.getElementById(''size-14'').onclick = size14; document.getElementById(''size-16'').onclick = size16;

Fiddle

Estoy trying todo lo posible para envolver mi cabeza alrededor de los cierres de JavaScript.

Obtengo que al devolver una función interna, tendrá acceso a cualquier variable definida en su matriz inmediata.

¿Dónde me sería útil? Tal vez todavía no haya logrado entenderlo. La mayoría de los ejemplos que he visto en línea no proporcionan ningún código del mundo real, solo ejemplos vagos.

¿Puede alguien mostrarme un uso real de un cierre?

¿Es éste, por ejemplo?

var warnUser = function (msg) { var calledCount = 0; return function() { calledCount++; alert(msg + ''/nYou have been warned '' + calledCount + '' times.''); }; }; var warnForTamper = warnUser(''You can not tamper with our HTML.''); warnForTamper(); warnForTamper();


Aquí tengo un ejemplo simple de concepto de cierre que podemos usar en nuestro sitio de comercio electrónico o en muchos otros. Estoy agregando mi enlace jsfiddle con el ejemplo. Contiene una pequeña lista de productos de 3 artículos y un contador de carrito.

Jsfiddle

//Counter clouser implemented function; var CartCouter = function(){ var counter = 0; function changeCounter(val){ counter += val } return { increment: function(){ changeCounter(1); }, decrement: function(){ changeCounter(-1); }, value: function(){ return counter; } } } var cartCount = CartCouter(); function updateCart(){ document.getElementById(''cartcount'').innerHTML = cartCount.value(); } var productlist = document.getElementsByClassName(''item''); for(var i = 0; i< productlist.length; i++){ productlist[i].addEventListener(''click'',function(){ if(this.className.indexOf(''selected'')<0){ this.className += " selected"; cartCount.increment(); updateCart(); } else{ this.className = this.className.replace("selected", ""); cartCount.decrement(); updateCart(); } }) }

.productslist{ padding:10px; } ul li{ display: inline-block; padding: 5px; border: 1px solid #ddd; text-align: center; width: 25%; cursor: pointer; } .selected{ background-color: #7CFEF0; color: #333; } .cartdiv{ position: relative; float:right; padding: 5px; box-sizing: border-box; border: 1px solid #f1f1f1; }

<div> <h3> Practical Use of JavaScript Closure consept/private variable. </h3> <div class="cartdiv"> <span id="cartcount">0</span> </div> <div class="productslist"> <ul > <li class="item">Product 1</li> <li class="item">Product 2</li> <li class="item">Product 3</li> </ul> </div> </div>


Aquí, tengo un saludo que quiero decir varias veces. Si creo un cierre, simplemente puedo llamar a esa función para grabar el saludo. Si no creo el cierre, tengo que pasar mi nombre cada vez.

Sin cierre ( https://jsfiddle.net/lukeschlangen/pw61qrow/3/ ):

function greeting(firstName, lastName) { var message = "Hello " + firstName + " " + lastName + "!"; console.log(message); } greeting("Billy", "Bob"); greeting("Billy", "Bob"); greeting("Billy", "Bob"); greeting("Luke", "Schlangen"); greeting("Luke", "Schlangen"); greeting("Luke", "Schlangen");

Con un cierre ( https://jsfiddle.net/lukeschlangen/Lb5cfve9/3/ ):

function greeting(firstName, lastName) { var message = "Hello " + firstName + " " + lastName + "!"; return function() { console.log(message); } } var greetingBilly = greeting("Billy", "Bob"); var greetingLuke = greeting("Luke", "Schlangen"); greetingBilly(); greetingBilly(); greetingBilly(); greetingLuke(); greetingLuke(); greetingLuke();


El ejemplo que das es excelente. Los cierres son un mecanismo de abstracción que le permite separar preocupaciones de manera muy limpia. Su ejemplo es un caso de separación de la instrumentación (recuento de llamadas) de la semántica (una API de informe de errores). Otros usos incluyen:

  1. Pasar el comportamiento parametrizado a un algoritmo (programación clásica de orden superior):

    function proximity_sort(arr, midpoint) { arr.sort(function(a, b) { a -= midpoint; b -= midpoint; return a*a - b*b; }); }

  2. Simulación de programación orientada a objetos:

    function counter() { var a = 0; return { inc: function() { ++a; }, dec: function() { --a; }, get: function() { return a; }, reset: function() { a = 0; } } }

  3. Implementar un control de flujo exótico, como el manejo de eventos de jQuery y las API de AJAX.


El patrón del módulo de JavaScript utiliza cierres. Su buen patrón te permite tener algo similar a las versiones "públicas" y "privadas".

var myNamespace = (function () { var myPrivateVar, myPrivateMethod; // A private counter variable myPrivateVar = 0; // A private function which logs any arguments myPrivateMethod = function( foo ) { console.log( foo ); }; return { // A public variable myPublicVar: "foo", // A public function utilizing privates myPublicFunction: function( bar ) { // Increment our private counter myPrivateVar++; // Call our private method using bar myPrivateMethod( bar ); } }; })();


En el lenguaje JavaScript (o cualquier ECMAScript), en particular, los cierres son útiles para ocultar la implementación de la funcionalidad y al mismo tiempo revelar la interfaz.

Por ejemplo, imagine que está escribiendo una clase de métodos de utilidad de fecha y desea permitir a los usuarios buscar nombres de días de la semana por índice, pero no desea que puedan modificar la matriz de nombres que utiliza debajo del capó.

var dateUtil = { weekdayShort: (function() { var days = [''Mon'', ''Tue'', ''Wed'', ''Thu'', ''Fri'', ''Sat'', ''Sun'']; return function(x) { if ((x != parseInt(x)) || (x < 1) || (x > 7)) { throw new Error("invalid weekday number"); } return days[x - 1]; }; }()) };

Tenga en cuenta que la matriz de days podría simplemente almacenarse como una propiedad del objeto dateUtil pero luego sería visible para los usuarios de la secuencia de comandos e incluso podrían cambiarla si lo desearan, sin siquiera necesitar su código fuente. Sin embargo, dado que está encerrada por la función anónima que devuelve la función de búsqueda de fecha, solo se puede acceder a ella mediante la función de búsqueda, por lo que ahora está a prueba de manipulaciones.


En la muestra dada, el valor de la variable adjunta ''contador'' está protegido y se puede modificar solo usando las funciones dadas (incremento, decremento). porque está en un cierre,

var MyCounter= function (){ var counter=0; return { increment:function () {return counter += 1;}, decrement:function () {return counter -= 1;}, get:function () {return counter;} }; }; var x = MyCounter(); //or var y = MyCounter(); alert(x.get());//0 alert(x.increment());//1 alert(x.increment());//2 alert(y.increment());//1 alert(x.get());// x is still 2


Este hilo me ha ayudado enormemente a comprender mejor cómo funcionan los cierres. Desde entonces, he realizado algunos experimentos por mi cuenta y he creado este código bastante simple que puede ayudar a otras personas a ver cómo se pueden usar los cierres de una manera práctica y cómo usar el cierre en diferentes niveles para mantener variables similares a las estáticas y / o variables globales sin riesgo de que se sobrescriban o se confundan con variables globales. Lo que esto hace es hacer un seguimiento de los clics de los botones, tanto a nivel local para cada botón individual como a nivel global, contando cada clic del botón, contribuyendo a una sola figura. Tenga en cuenta que no he usado ninguna variable global para hacer esto, que es la clase de punto del ejercicio: tener un controlador que se puede aplicar a cualquier botón que también contribuya a algo global.

Por favor, expertos, háganme saber si he cometido alguna mala práctica aquí. Todavía estoy aprendiendo estas cosas yo mismo.

<!doctype html> <html> <head> <meta charset="utf-8"> <title>Closures on button presses</title> <script type="text/javascript"> window.addEventListener("load" , function () { /* grab the function from the first closure, and assign to a temporary variable this will set the totalButtonCount variable that is used to count the total of all button clicks */ var buttonHandler = buttonsCount(); /* using the result from the first closure (a function is returned) assign and run the sub closure that carries the individual variable for button count and assign to the click handlers */ document.getElementById("button1").addEventListener("click" , buttonHandler() ); document.getElementById("button2").addEventListener("click" , buttonHandler() ); document.getElementById("button3").addEventListener("click" , buttonHandler() ); // Now that buttonHandler has served its purpose it can be deleted if needs be buttonHandler = null; }); function buttonsCount() { /* First closure level - totalButtonCount acts as a sort of global counter to count any button presses */ var totalButtonCount = 0; return function () { //second closure level var myButtonCount = 0; return function (event) { //actual function that is called on the button click event.preventDefault(); /* increment the button counts. myButtonCount only exists in the scope that is applied to each event handler, therefore acts to count each button individually whereas because of the first closure totalButtonCount exists at the scope just outside, so maintains a sort of static or global variable state */ totalButtonCount++; myButtonCount++; /* do something with the values ... fairly pointless but it shows that each button contributes to both it''s own variable and the outer variable in the first closure */ console.log("Total button clicks: "+totalButtonCount); console.log("This button count: "+myButtonCount); } } } </script> </head> <body> <a href="#" id="button1">Button 1</a> <a href="#" id="button2">Button 2</a> <a href="#" id="button3">Button 3</a> </body> </html>




He usado cierres para hacer cosas como:

a = (function () { var privatefunction = function () { alert(''hello''); } return { publicfunction : function () { privatefunction(); } } })();

Como puede ver allí, a es ahora un objeto, con un método publicfunction ( a.publicfunction() ) que llama a privatefunction , que solo existe dentro del cierre. NO se puede llamar a la función privatefunction directamente (es decir, una función a.privatefunction() ), solo la función publicfunction() .

Es un ejemplo mínimo, pero tal vez usted puede ver los usos? Usamos esto para imponer métodos públicos / privados.


Los cierres son una forma útil de crear generators , una secuencia incrementada a pedido:

var foobar = function(i){var count = count || i; return function(){return ++count;}} baz = foobar(1); console.log("first call: " + baz()); //2 console.log("second call: " + baz()); //3

Las diferencias se resumen a continuación:

Anonymous functions Defined functions Cannot be used as a method Can be used as a method of an object Exists only in the scope in which it is defined Exists within the object it is defined in Can only be called in the scope in which it is defined Can be called at any point in the code Can be reassigned a new value or deleted Cannot be deleted or changed

Referencias


Me gusta el example fábrica de funciones de Mozilla.

function makeAdder(x) { return function(y) { return x + y; }; } var addFive = makeAdder(5); console.assert(addFive(2) === 7); console.assert(addFive(-5) === 0);


Otro uso común de los cierres es vincular this en un método a un objeto específico, permitiendo que se llame a otra parte (como un controlador de eventos).

function bind(obj, method) { if (typeof method == ''string'') { method = obj[method]; } return function () { method.apply(obj, arguments); } } ... document.body.addEventListener(''mousemove'', bind(watcher, ''follow''), true);

Cada vez que se dispara un evento mousemove, se watcher.follow(evt) .

Los cierres también son una parte esencial de las funciones de orden superior, permitiendo el patrón muy común de reescribir múltiples funciones similares como una sola función de orden superior mediante la parametrización de las partes diferentes. Como ejemplo abstracto,

foo_a = function (...) {A a B} foo_b = function (...) {A b B} foo_c = function (...) {A c B}

se convierte en

fooer = function (x) { return function (...) {A x B} }

donde A y B no son unidades sintácticas sino cadenas de código fuente (no literales de cadena).

Consulte " Racionalizar mi javascript con una función " para ver un ejemplo concreto.


Referencia: Uso práctico de los cierres.

En la práctica, los cierres pueden crear diseños elegantes, lo que permite la personalización de varios cálculos, llamadas diferidas, devoluciones de llamadas, creación de alcance encapsulado, etc.

Un ejemplo del método de clasificación de matrices que acepta como argumento la función de clasificación-condición:

[1, 2, 3].sort(function (a, b) { ... // sort conditions });

Funciones de asignación como el método de asignación de matrices que asigna una nueva matriz según la condición del argumento funcional:

[1, 2, 3].map(function (element) { return element * 2; }); // [2, 4, 6]

A menudo es conveniente implementar funciones de búsqueda utilizando argumentos funcionales que definen condiciones casi ilimitadas para la búsqueda:

someCollection.find(function (element) { return element.someProperty == ''searchCondition''; });

Además, podemos observar la aplicación de funciones como, por ejemplo, un método forEach que aplica una función a una matriz de elementos:

[1, 2, 3].forEach(function (element) { if (element % 2 != 0) { alert(element); } }); // 1, 3

Una función se aplica a los argumentos (a una lista de argumentos - en aplicar y a los argumentos posicionados - en llamada):

(function () { alert([].join.call(arguments, '';'')); // 1;2;3 }).apply(this, [1, 2, 3]);

Llamadas diferidas:

var a = 10; setTimeout(function () { alert(a); // 10, after one second }, 1000);

Funciones de devolución de llamada:

var x = 10; // only for example xmlHttpRequestObject.onreadystatechange = function () { // callback, which will be called deferral , // when data will be ready; // variable "x" here is available, // regardless that context in which, // it was created already finished alert(x); // 10 };

Creación de un ámbito encapsulado con el fin de ocultar objetos auxiliares:

var foo = {}; (function (object) { var x = 10; object.getX = function _getX() { return x; }; })(foo); alert(foo.getX());// get closured "x" – 10


Sé que llego muy tarde para responder esta pregunta, pero podría ayudar a cualquiera que busque la respuesta en 2018.

Los cierres de Javascript se pueden usar para implementar las funciones de aceleración y rebote en su aplicación.

Estrangulamiento

La limitación pone un límite como el número máximo de veces que se puede llamar a una función a lo largo del tiempo. Como en "ejecutar esta función como máximo una vez cada 100 milisegundos".

Código:

const throttle = (func, limit) => { let isThrottling return function() { const args = arguments const context = this if (!isThrottling) { func.apply(context, args) isThrottling = true setTimeout(() => isThrottling = false, limit) } } }

Que denuncia

No se debe volver a llamar a una función para anunciar un límite hasta que haya transcurrido cierto tiempo sin que se llame. Como en "ejecutar esta función solo si han transcurrido 100 milisegundos sin que se llame".

Código:

const debounce = (func, delay) => { let debouncing return function() { const context = this const args = arguments clearTimeout(debouncing) debouncing = setTimeout(() => func.apply(context, args), delay) } }

Como puede ver, los cierres ayudaron a implementar dos hermosas características que cada aplicación web debería tener para proporcionar una funcionalidad de experiencia de interfaz de usuario sin problemas.

Espero que ayude a alguien.


Sí, ese es un buen ejemplo de un cierre útil. La llamada a warnUser crea la variable calledCount en su alcance y devuelve una función anónima que se almacena en la variable warnForTamper . Debido a que todavía hay un cierre que utiliza la variable calledCount, no se elimina al salir de la función, por lo que cada llamada a warnForTamper() aumentará la variable de ámbito y alertará el valor.

El problema más común que veo en es cuando alguien quiere "retrasar" el uso de una variable que se incrementa en cada bucle, pero debido a que la variable tiene un alcance, cada referencia a la variable sería después de que el bucle haya finalizado, lo que da como resultado Estado final de la variable:

for (var i = 0; i < someVar.length; i++) window.setTimeout(function () { alert("Value of i was "+i+" when this timer was set" ) }, 10000);

Esto daría como resultado que cada alerta muestre el mismo valor de i , el valor al que se incrementó cuando finalizó el ciclo. La solución es crear un nuevo cierre, un ámbito separado para la variable. Esto se puede hacer usando una función anónima ejecutada instantáneamente, que recibe la variable y almacena su estado como un argumento:

for (var i = 0; i < someVar.length; i++) (function (i) { window.setTimeout(function () { alert("Value of i was "+i+" when this timer was set" ) }, 10000); })(i);


Si se siente cómodo con el concepto de crear una instancia de una clase en el sentido orientado a objetos (es decir, para crear un objeto de esa clase), entonces está cerca de comprender los cierres.

Piénselo de esta manera: cuando crea una instancia de dos objetos Person, sabe que la variable miembro de la clase "Nombre" no se comparte entre las instancias; Cada objeto tiene su propia ''copia''. De manera similar, cuando crea un cierre, la variable libre (''calledCount'' en su ejemplo anterior) está vinculada a la ''instancia'' de la función.

Creo que su salto conceptual se ve ligeramente obstaculizado por el hecho de que cada función / cierre devuelto por la función warnUser (aparte: es una función de orden superior ), el cierre se enlaza con el mismo valor inicial (0), mientras que a menudo se crean cierres. es más útil pasar diferentes inicializadores a la función de orden superior, al igual que pasar diferentes valores al constructor de una clase.

Por lo tanto, supongamos que cuando ''calledCount'' alcanza un cierto valor desea finalizar la sesión del usuario; es posible que desee diferentes valores para eso, dependiendo de si la solicitud proviene de la red local o del gran mal internet (sí, es un ejemplo artificial). Para lograr esto, puede pasar diferentes valores iniciales para calledCount en warnUser (es decir, -3, o 0?).

Parte del problema con la literatura es la nomenclatura utilizada para describirlos ("alcance léxico", "variables libres"). No dejes que te engañe, los cierres son más simples de lo que parece ... prima facie ;-)


Supongamos que desea contar la cantidad de veces que un usuario hizo clic en un botón en una página web.
Para esto, está activando una función en el evento onclick del botón para actualizar el conteo de la variable

<button onclick="updateClickCount()">click me</button>

Ahora podría haber muchos enfoques como:

1) Podría usar una variable global y una función para aumentar el contador :

var counter = 0; function updateClickCount() { ++counter; // do something with counter }

Pero, el inconveniente es que cualquier secuencia de comandos en la página puede cambiar el contador, sin llamar a updateClickCount() .

2) Ahora, podría estar pensando en declarar la variable dentro de la función:

function updateClickCount() { var counter = 0; ++counter; // do something with counter }

¡Pero hey! Cada vez que se llama a la función updateClickCount() , el contador se establece de nuevo en 1.

3) ¿Pensando en funciones anidadas ?

Las funciones anidadas tienen acceso al ámbito "por encima" de ellas.
En este ejemplo, la función interna updateClickCount() tiene acceso a la variable de contador en la función principal countWrapper()

function countWrapper() { var counter = 0; function updateClickCount() { ++counter; // do something with counter } updateClickCount(); return counter; }

Esto podría haber resuelto el problema del contador, si pudiera alcanzar la función updateClickCount() desde el exterior y también necesita encontrar una forma de ejecutar counter = 0 solo una vez, no siempre.

4) ¡ Cierre al rescate! (función de auto-invocación) :

var updateClickCount=(function(){ var counter=0; return function(){ ++counter; // do something with counter } })();

La función de auto-invocación solo se ejecuta una vez. Establece el counter en cero (0) y devuelve una expresión de función.

De esta manera updateClickCount convierte en una función. La parte "maravillosa" es que puede acceder al contador en el ámbito principal.

Esto se llama un cierre de JavaScript . Permite que una función tenga variables " privadas ".

El counter está protegido por el alcance de la función anónima, ¡y solo se puede cambiar usando la función agregar!

Ejemplo más animado de cierre:

<script> var updateClickCount=(function(){ var counter=0; return function(){ ++counter; document.getElementById("spnCount").innerHTML=counter; } })(); </script> <html> <button onclick="updateClickCount()">click me</button> <div> you''ve clicked <span id="spnCount"> 0 </span> times! </div> </html>


Uso de los cierres:

Los cierres son una de las características más poderosas de JavaScript. JavaScript permite anidar funciones y otorga a la función interna acceso total a todas las variables y funciones definidas dentro de la función externa (y todas las demás variables y funciones a las que la función externa tiene acceso). Sin embargo, la función externa no tiene acceso a las variables y funciones definidas dentro de la función interna. Esto proporciona una especie de seguridad para las variables de la función interna. Además, como la función interna tiene acceso al alcance de la función externa, las variables y funciones definidas en la función externa vivirán más tiempo que la función externa en sí misma, si la función interna logra sobrevivir más allá de la vida de la función externa. Se crea un cierre cuando la función interna se pone de alguna manera a disposición de cualquier ámbito fuera de la función externa.

Ejemplo:

<script> var createPet = function(name) { var sex; return { setName: function(newName) { name = newName; }, getName: function() { return name; }, getSex: function() { return sex; }, setSex: function(newSex) { if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) { sex = newSex; } } } } var pet = createPet("Vivie"); console.log(pet.getName()); // Vivie console.log(pet.setName("Oliver")); console.log(pet.setSex("male")); console.log(pet.getSex()); // male console.log(pet.getName()); // Oliver </script>

En el código anterior, la variable de nombre de la función externa es accesible a las funciones internas, y no hay otra manera de acceder a las variables internas excepto a través de las funciones internas. Las variables internas de la función interna actúan como almacenes seguros para las funciones internas. Contienen datos "persistentes", pero seguros, para las funciones internas con las que trabajar. Las funciones ni siquiera tienen que asignarse a una variable, o tener un nombre. lee here para más detalles