1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
|
---
title: Chiusure
slug: Web/JavaScript/Closures
translation_of: Web/JavaScript/Closures
original_slug: Web/JavaScript/Chiusure
---
<div>{{jsSidebar("Intermediate")}}</div>
<div></div>
<p class="summary">Una <strong>closure</strong> è la combinazione di una funzione e dello stato nella quale è stata creata (ambito lessicale). In altre parole, una <strong>closure</strong> consente a una funzione interna di accedere allo scope della funzione che la racchiude. In Javascript le <strong>closure</strong> sono create ogni volta che una funzione viene creata, al momento della creazione della funzione stessa.</p>
<h2 id="Lexical_scoping">Lexical scoping</h2>
<p>Considerate la seguente:</p>
<div>
<pre class="brush: js notranslate">function init() {
var name = "Mozilla"; // name è una variabile locale creata da init
function displayName() { // displayName() è una funzione interna, una chiusura
alert(name); // utilizza la variabile dichiarata nella funzione padre
}
displayName();
}
init();</pre>
</div>
<p><code>init()</code> crea una variabile locale <code>name</code> e poi una funzione chiamata <code>displayName()</code>. <code>displayName()</code> è una funzione interna che è definita dentro <code>init()</code> ed è disponibile solo all'interno del corpo di quella funzione. <code>displayName()</code> non ha proprie variabili locali. Tuttavia, poiché le funzioni interne hanno accesso alle variabili di quelle esterne, <code>displayName()</code> può accedere alla variabile <code>name</code> dichiarata nella funzione genitore, <code>init()</code> Tuttavia verrebbero usate le variabili locali in <code>displayName()</code>, se esistessero.</p>
<p>{{JSFiddleEmbed("https://jsfiddle.net/78dg25ax/", "js,result", 200)}}</p>
<p><a href="http://jsfiddle.net/xAFs9/3/" title="http://jsfiddle.net/xAFs9/">Esegui</a> il codice e verifica che funziona. Questo è un esempio di <em>lexical</em> <em>scoping</em>: in JavaScript, la visibilità (scope) di una variabile è definita dalla sua posizione all'interno del codice sorgente (si evince dal codice stesso [<em>lexically</em>]) e le funzioni innestate hanno accesso a variabili dichiarate nella funzione esterna (outer scope).</p>
<h2 id="Closure">Closure</h2>
<p>Considerate ora l'esempio seguente:</p>
<pre class="brush: js notranslate">function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
</pre>
<p>L'esecuzione di questo codice ha esattamente lo stesso effetto dell'esempio precedente della funzione init(): la stringa "Mozilla" verrà visualizzata in una casella di avviso JavaScript. La cosa differente ed interessante, è che la funzione interna displayName() viene restituita dalla funzione esterna prima di essere eseguita.</p>
<p>A un primo sguardo sembrerebbe controintuitivo che il codice funzioni ancora. In alcuni linguaggi di programmazione le variabili locali interne a una funzione esistono solo per la durata dell'esecuzione della funzione stessa. Una volta che <code>makeFunc()</code> ha terminato la propria esecuzione, ci si potrebbe aspettare che la variabile name non sia più accessibile. Tuttavia, poiché il codice funziona ancora, è ovvio che in JavaScript non è il caso.</p>
<p>La ragione è che le funzioni in JavaScript formano closures. Una <em>closure </em>è la combinazione di una funzione e dell'ambito lessicale in cui questa funzione è stata dichiarata. In questo caso, <code>myFunc</code> è un riferimento all'istanza della funzione displayName creata quando <code>makeFunc</code> è eseguita.</p>
<p>La soluzione di questo rompicampo è che <code>myFunc</code> è diventata una <em>closure</em>. Una closure è uno speciale tipo di oggetto che combina due cose: una funzione e l'ambito in cui questa è stata creata. L'ambito consiste in qualsiasi variabile locale che era nel suo scope nel momento in cui la closure è stata creata. In questo caso, <code>myFunc</code> è una <em>closure </em>che incorpora sia la funzione <code>displayName</code> che la stringa "Mozilla", già esistente quando la closure è stata creata.</p>
<p>Ecco un esempio leggermente più interessante — una funzione <code>makeAdder</code>:</p>
<pre class="brush: js notranslate">function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
</pre>
<p>In questo esempio, abbiamo definito una funzione <code>makeAdder(x)</code> che prende un singolo argomento <code>x</code> e restituisce una nuova funzione. La funzione restituita prende un singolo argomento <code>y</code>, e restituisce la somma tra <code>x</code> e <code>y</code>.</p>
<p>In sostanza, <code>makeAdder</code> è una <em>factory function </em>— crea funzioni che possono aggiungere uno specifico valore come argomento. Nell'esempio sopra usiamo la nostra factory function per creare due nuove funzioni — una che aggiunge 5 ai suoi argomenti, e una che aggiunge 10.</p>
<p><code>add5</code> e <code>add10</code> sono entrambe <em>closures</em>. Condividono la stessa definizione del corpo della funzione, ma memorizzano diversi ambienti. Nell'ambiente di <code>add5</code>, <code>x</code> vale 5. Per quanto riguarda <code>add10</code> , <code>x</code> vale 10.</p>
<h2 id="Practical_closures">Practical closures</h2>
<p>That's the theory of closures — but are closures actually useful? Let's consider their practical implications. A closure lets you associate some data (the environment) with a function that operates on that data. This has obvious parallels to object oriented programming, where objects allow us to associate some data (the object's properties) with one or more methods.</p>
<p>Consequently, you can use a closure anywhere that you might normally use an object with only a single method.</p>
<p>Situations where you might want to do this are particularly common on the web. Much of the code we write in web JavaScript is event-based — we define some behavior, then attach it to an event that is triggered by the user (such as a click or a keypress). Our code is generally attached as a callback: a single function which is executed in response to the event.</p>
<p>Here's a practical example: suppose we wish to add some buttons to a page that adjust the text size. One way of doing this is to specify the font-size of the body element in pixels, then set the size of the other elements on the page (such as headers) using the relative em unit:</p>
<pre class="brush: css notranslate">body {
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
}
h1 {
font-size: 1.5em;
}
h2 {
font-size: 1.2em;
}
</pre>
<p>Our interactive text size buttons can change the font-size property of the body element, and the adjustments will be picked up by other elements on the page thanks to the relative units.</p>
<p>Qui c'è il codice JavaScript:</p>
<pre class="brush: js notranslate">function makeSizer(size) {
return function() {
document.body.style.fontSize = size + 'px';
};
}
var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);
</pre>
<p><code>size12</code>, <code>size14</code>, and <code>size16</code> are now functions which will resize the body text to 12, 14, and 16 pixels, respectively. We can attach them to buttons (in this case links) as follows:</p>
<pre class="brush: js notranslate">document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
</pre>
<pre class="brush: html notranslate"><a href="#" id="size-12">12</a>
<a href="#" id="size-14">14</a>
<a href="#" id="size-16">16</a>
</pre>
<p>{{JSFiddleEmbed("https://jsfiddle.net/vnkuZ/","","200")}}</p>
<h2 id="Emulare_metodi_privati_con_chiusure">Emulare metodi privati con chiusure</h2>
<p>Languages such as Java provide the ability to declare methods private, meaning that they can only be called by other methods in the same class.</p>
<p>JavaScript does not provide a native way of doing this, but it is possible to emulate private methods using closures. Private methods aren't just useful for restricting access to code: they also provide a powerful way of managing your global namespace, keeping non-essential methods from cluttering up the public interface to your code.</p>
<p>Here's how to define some public functions that can access private functions and variables, using closures which is also known as the <a class="external" href="http://www.google.com/search?q=javascript+module+pattern" title="http://www.google.com/search?q=javascript+module+pattern">module pattern</a>:</p>
<pre class="brush: js notranslate">var counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
};
})();
console.log(counter.value()); // logs 0
counter.increment();
counter.increment();
console.log(counter.value()); // logs 2
counter.decrement();
console.log(counter.value()); // logs 1
</pre>
<p>There's a lot going on here. In previous examples each closure has had its own environment; here we create a single environment which is shared by three functions: <code>counter.increment</code>, <code>counter.decrement</code>, and <code>counter.value</code>.</p>
<p>The shared environment is created in the body of an anonymous function, which is executed as soon as it has been defined. The environment contains two private items: a variable called <code>privateCounter</code> and a function called <code>changeBy</code>. Neither of these private items can be accessed directly from outside the anonymous function. Instead, they must be accessed by the three public functions that are returned from the anonymous wrapper.</p>
<p>Those three public functions are closures that share the same environment. Thanks to JavaScript's lexical scoping, they each have access to the <code>privateCounter</code> variable and <code>changeBy</code> function.</p>
<p>You'll notice we're defining an anonymous function that creates a counter, and then we call it immediately and assign the result to the <code>counter</code> variable. We could store this function in a separate variable <code>makeCounter</code> and use it to create several counters.</p>
<pre class="brush: js notranslate">var makeCounter = function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
};
var counter1 = makeCounter();
var counter2 = makeCounter();
alert(counter1.value()); /* Alerts 0 */
counter1.increment();
counter1.increment();
alert(counter1.value()); /* Alerts 2 */
counter1.decrement();
alert(counter1.value()); /* Alerts 1 */
alert(counter2.value()); /* Alerts 0 */
</pre>
<p>Notice how each of the two counters maintains its independence from the other. Its environment during the call of the <code>makeCounter()</code> function is different each time. The closure variable <code>privateCounter </code>contains a different instance each time.</p>
<p>Using closures in this way provides a number of benefits that are normally associated with object oriented programming, in particular data hiding and encapsulation.</p>
<h2 id="Creating_closures_in_loops_A_common_mistake">Creating closures in loops: A common mistake</h2>
<p>Prior to the introduction of the <a href="/en-US/docs/Web/JavaScript/Reference/Statements/let" title="let"><code>let</code> keyword</a> in ECMAScript 6, a common problem with closures occurred when they were created inside a loop. Consider the following example:</p>
<pre class="brush: html notranslate"><p id="help">Helpful notes will appear here</p>
<p>E-mail: <input type="text" id="email" name="email"></p>
<p>Name: <input type="text" id="name" name="name"></p>
<p>Age: <input type="text" id="age" name="age"></p>
</pre>
<pre class="brush: js notranslate">function showHelp(help) {
document.getElementById('help').innerHTML = help;
}
function setupHelp() {
var helpText = [
{'id': 'email', 'help': 'Your e-mail address'},
{'id': 'name', 'help': 'Your full name'},
{'id': 'age', 'help': 'Your age (you must be over 16)'}
];
for (var i = 0; i < helpText.length; i++) {
var item = helpText[i];
document.getElementById(item.id).onfocus = function() {
showHelp(item.help);
}
}
}
setupHelp();
</pre>
<p>{{JSFiddleEmbed("https://jsfiddle.net/v7gjv/", "", 200)}}</p>
<p>The <code>helpText</code> array defines three helpful hints, each associated with the ID of an input field in the document. The loop cycles through these definitions, hooking up an onfocus event to each one that shows the associated help method.</p>
<p>If you try this code out, you'll see that it doesn't work as expected. No matter what field you focus on, the message about your age will be displayed.</p>
<p>The reason for this is that the functions assigned to <code>onfocus</code> are closures; they consist of the function definition and the captured environment from the <code>setupHelp</code> function's scope. Three closures have been created, but each one shares the same single environment. By the time the <code>onfocus</code> callbacks are executed, the loop has run its course and the item variable (shared by all three closures) has been left pointing to the last entry in the <code>helpText</code> list.</p>
<p>One solution in this case is to use more closures: in particular, to use a function factory as described earlier on:</p>
<pre class="brush: js notranslate">function showHelp(help) {
document.getElementById('help').innerHTML = help;
}
function makeHelpCallback(help) {
return function() {
showHelp(help);
};
}
function setupHelp() {
var helpText = [
{'id': 'email', 'help': 'Your e-mail address'},
{'id': 'name', 'help': 'Your full name'},
{'id': 'age', 'help': 'Your age (you must be over 16)'}
];
for (var i = 0; i < helpText.length; i++) {
var item = helpText[i];
document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
}
}
setupHelp();
</pre>
<p>{{JSFiddleEmbed("https://jsfiddle.net/v7gjv/1/", "", 300)}}</p>
<p>This works as expected. Rather than the callbacks all sharing a single environment, the <code>makeHelpCallback</code> function creates a new environment for each one in which <code>help</code> refers to the corresponding string from the <code>helpText</code> array.</p>
<h2 id="Performance_considerations">Performance considerations</h2>
<p>It is unwise to unnecessarily create functions within other functions if closures are not needed for a particular task, as it will negatively affect script performance both in terms of processing speed and memory consumption.</p>
<p>For instance, when creating a new object/class, methods should normally be associated to the object's prototype rather than defined into the object constructor. The reason is that whenever the constructor is called, the methods would get reassigned (that is, for every object creation).</p>
<p>Consider the following impractical but demonstrative case:</p>
<pre class="brush: js notranslate">function MyObject(name, message) {
this.name = name.toString();
this.message = message.toString();
this.getName = function() {
return this.name;
};
this.getMessage = function() {
return this.message;
};
}
</pre>
<p>The previous code does not take advantage of the benefits of closures and thus could instead be formulated:</p>
<pre class="brush: js notranslate">function MyObject(name, message) {
this.name = name.toString();
this.message = message.toString();
}
MyObject.prototype = {
getName: function() {
return this.name;
},
getMessage: function() {
return this.message;
}
};
</pre>
<p>However, redefining the prototype is not recommended, so the following example is even better because it appends to the existing prototype:</p>
<pre class="brush: js notranslate">function MyObject(name, message) {
this.name = name.toString();
this.message = message.toString();
}
MyObject.prototype.getName = function() {
return this.name;
};
MyObject.prototype.getMessage = function() {
return this.message;
};
</pre>
<p>Il codice sopra può essere riscritto meglio in un modo più pulito, con lo stesso risultato:</p>
<pre class="brush: js notranslate">function MyObject(name, message) {
this.name = name.toString();
this.message = message.toString();
}
(function() {
this.getName = function() {
return this.name;
};
this.getMessage = function() {
return this.message;
};
}).call(MyObject.prototype);
</pre>
<p>In the two previous examples, the inherited prototype can be shared by all objects and the method definitions need not occur at every object creation. See <a href="/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model">Details of the Object Model</a> for more details.</p>
|