You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Let's examine what exactly happens inside `makeArmy`, and the solution will become obvious.
2
+
Esaminiamo cosa accade dentro `makeArmy`, e la soluzioni ci apparirà ovvia.
3
3
4
-
1.It creates an empty array `shooters`:
4
+
1.Crea un array vuoto`shooters`:
5
5
6
6
```js
7
7
let shooters = [];
8
8
```
9
-
2.Fills it with functions via`shooters.push(function)`in the loop.
9
+
2.Lo riempie con un ciclo`shooters.push(function...)`.
10
10
11
-
Every element is a function, so the resulting array looks like this:
11
+
Ogni elemento è una funzione, quindi l'array finale risulterà essere:
12
12
13
13
```js no-beautify
14
14
shooters = [
@@ -25,105 +25,96 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco
25
25
];
26
26
```
27
27
28
-
3. The array is returned from the function.
29
-
30
-
Then, later, the call to any member, e.g. `army[5]()` will get the element `army[5]` from the array (which is a function) and calls it.
31
-
32
-
Now why do all such functions show the same value, `10`?
33
-
34
-
That's because there's no local variable `i` inside `shooter` functions. When such a function is called, it takes `i` from its outer lexical environment.
35
-
36
-
Then, what will be the value of `i`?
37
-
38
-
If we look at the source:
39
-
40
-
```js
41
-
function makeArmy() {
42
-
...
43
-
let i =0;
44
-
while (i <10) {
45
-
letshooter=function() { // shooter function
46
-
alert( i ); // should show its number
47
-
};
48
-
shooters.push(shooter); // add function to the array
49
-
i++;
50
-
}
51
-
...
52
-
}
53
-
```
54
-
55
-
We can see that all `shooter` functions are created in the lexical environment of`makeArmy()`function. But when `army[5]()` is called, `makeArmy` has already finished its job, and the final value of `i` is `10` (`while` stops at `i=10`).
56
-
57
-
As the result, all `shooter` functions get the same value from the outer lexical environment and that is, the last value, `i=10`.
58
-
59
-

60
-
61
-
As you can see above, on each iteration of a `while {...}` block, a new lexical environment is created. So, to fix this, we can copy the value of `i` into a variable within the `while {...}` block, like this:
62
-
63
-
```js run
64
-
functionmakeArmy() {
65
-
let shooters = [];
66
-
67
-
let i =0;
68
-
while (i <10) {
69
-
*!*
70
-
let j = i;
71
-
*/!*
72
-
letshooter=function() { // shooter function
73
-
alert( *!*j*/!* ); // should show its number
74
-
};
75
-
shooters.push(shooter);
76
-
i++;
77
-
}
78
-
79
-
return shooters;
80
-
}
81
-
82
-
let army =makeArmy();
83
-
84
-
// Now the code works correctly
85
-
army[0](); // 0
86
-
army[5](); // 5
87
-
```
88
-
89
-
Here `let j = i` declares an "iteration-local" variable `j` and copies `i` into it. Primitives are copied "by value", so we actually get an independent copy of `i`, belonging to the current loop iteration.
90
-
91
-
The shooters work correctly, because the value of `i` now lives a little bit closer. Not in `makeArmy()` Lexical Environment, but in the Lexical Environment that corresponds the current loop iteration:
92
-
93
-

94
-
95
-
Such problem could also be avoided if we used `for` in the beginning, like this:
96
-
97
-
```js run demo
98
-
functionmakeArmy() {
99
-
100
-
let shooters = [];
101
-
102
-
*!*
103
-
for(let i =0; i <10; i++) {
104
-
*/!*
105
-
letshooter=function() { // shooter function
106
-
alert( i ); // should show its number
107
-
};
108
-
shooters.push(shooter);
109
-
}
110
-
111
-
return shooters;
112
-
}
113
-
114
-
let army =makeArmy();
115
-
116
-
army[0](); // 0
117
-
army[5](); // 5
118
-
```
119
-
120
-
That's essentially the same, because `for` on each iteration generates a new lexical environment, with its own variable `i`. So `shooter` generated in every iteration references its own `i`, from that very iteration.
121
-
122
-

28
+
3. L'array viene ritornato dalla funzione.
29
+
30
+
Successivamente, la chiamata `army[5]()` otterrà l'elemento `army[5]` dall'array (cioè una funzione) e la invocherà.
31
+
32
+
Ora perchè tutte le funzione mostrano lo stesso risultato?
33
+
34
+
Questo accade perchè non c'è alcuna variabile locale `i` interna alla funzione `shooter`. Quando questa funzione viene invocata, prende `i` dal lexical environment esterno.
35
+
36
+
Quale sarà il valore di `i`?
37
+
38
+
Se guardiamo il codice:
39
+
40
+
```js
41
+
function makeArmy() {
42
+
...
43
+
let i = 0;
44
+
while (i < 10) {
45
+
let shooter = function() { // shooter function
46
+
alert( i ); // should show its number
47
+
};
48
+
...
49
+
}
50
+
...
51
+
}
52
+
```
53
+
54
+
...Notiamo che si trova nel lexival environment associato a `makeArmy()`. Ma quando invochiamo `army[5]()`, `makeArmy` ha già terminato l'esecuzione, e `i` possiede l'ultimo valore: `10`.
55
+
56
+
Il risultato è che tutte le funzioni `shooter` la prendono dallo stesso lexical envrironment esterno, in cui l'ultimo valore è `i=10`.
57
+
58
+
Questo può essere sistemato molto facilmente:
59
+
60
+
```js run
61
+
function makeArmy() {
62
+
63
+
let shooters = [];
64
+
65
+
*!*
66
+
for(let i = 0; i < 10; i++) {
67
+
*/!*
68
+
let shooter = function() { // shooter function
69
+
alert( i ); // should show its number
70
+
};
71
+
shooters.push(shooter);
72
+
}
73
+
74
+
return shooters;
75
+
}
76
+
77
+
let army = makeArmy();
78
+
79
+
army[0](); // 0
80
+
army[5](); // 5
81
+
```
82
+
Ora funziona correttamente, perché ogni volta che viene eseguito il blocco di codice `for (..) {...}`, viene creato un nuovo Lexical Environment, con il corrispondente valore `i`.
83
+
84
+
Quindi, il valore di `i` ora si trova più "vicino". Non più nel lexical environment di `makeArmy()`, ma in quello del corrispondente ciclo. Uno`shooter` preleva il valore esattamente da dove è stato creato.
85
+
86
+

87
+
88
+
Qui abbiamo riscritto `while`in`for`.
89
+
90
+
Eì possibile farlo in un altro modo, vediamolo per capirlo meglio:
91
+
92
+
93
+
```js run
94
+
function makeArmy() {
95
+
let shooters = [];
96
+
97
+
let i = 0;
98
+
while (i < 10) {
99
+
*!*
100
+
let j = i;
101
+
*/!*
102
+
let shooter = function() { // shooter function
103
+
alert( *!*j*/!* ); // should show its number
104
+
};
105
+
shooters.push(shooter);
106
+
i++;
107
+
}
108
+
109
+
return shooters;
110
+
}
123
111
124
-
Now, as you've put so much effort into reading this, and the final recipe is so simple - just use `for`, you may wonder -- was it worth that?
112
+
let army = makeArmy();
125
113
126
-
Well, if you could easily answer the question, you wouldn't read the solution. So, hopefully this task must have helped you to understand things a bit better.
114
+
army[0](); // 0
115
+
army[5](); // 5
116
+
```
127
117
128
-
Besides, there are indeed cases when one prefers `while` to`for`, and other scenarios, where such problems are real.
118
+
Il ciclo `while`, come`for`, crea un nuovo Lexical Environment ad ogni esecuzone. Quindi siamo sicuri di ottener il giusto valore di `shooter`.
129
119
120
+
Copiamo `let j = i`. Questo rende il corpo del ciclo locale e copia su `j` il valore di `i`. Gli oggetti primitivi vengono copiati per valore, quindi ora abbiamo un copia indipendente di `i`, che appartiene all iterazione corrente.
0 commit comments