This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
A function gets outer variables as they are now, it uses the most recent values.
En funktion får ydre variabler som de er nu, den bruger de mest nyeste værdier.
Gamle variabelværdier gemmes ikke nogen steder. Når en funktion ønsker en variabel, tager den den nuværende værdi fra sit eget leksikale miljø eller det ydre.
Old variable values are not saved anywhere. When a function wants a variable, it takes the current value from its own Lexical Environment or the outer one.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The function sayHi uses an external variable name. When the function runs, which value is it going to use?
Funktionen sayHi bruger en ekstern variabel name. Når funktionen kører, hvilken værdi vil den bruge?
```js
let name = "John";
function sayHi() {
alert("Hi, " + name);
alert("Hej, " + name);
}
name = "Pete";
sayHi(); // what will it show: "John" or "Pete"?
sayHi(); // Hvad vil den vise: "John" eller "Pete"?
```
Such situations are common both in browser and server-side development. A function may be scheduled to execute later than it is created, for instance after a user action or a network request.
Sådanne situationer er udbredte både i browser- og server-side udvikling. En funktion kan blive planlagt til at køre senere end den blev oprettet, for eksempel efter en brugerhandling eller en netværksforespørgsel.
So, the question is: does it pick up the latest changes?
Så spørgsmålet er: vil den tage de seneste ændringer?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Let's examine what exactly happens inside `makeArmy`, and the solution will become obvious.
Lad os undersøge hvad der faktisk sker inde i `makeArmy`. Måske står løsningen så klarere.
1. It creates an empty array `shooters`:
1. Den opretter et tomt array `shooters`:
```js
let shooters = [];
```
2. Fills it with functions via `shooters.push(function)` in the loop.
2. Fylder den med funktioner via `shooters.push(function)` i løkken.
Every element is a function, so the resulting array looks like this:
Hvert element er en funktion, så det resulterer i et array der ser således ud:
```js no-beautify
shooters = [
Expand All
@@ -25,40 +25,38 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco
];
```
3. The array is returned from the function.
3. Arrayet returneres fra funktionen.
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.
Senere vil et kald til et element i arrayet, f.eks. `army[5]()` vil hente elementet `army[5]` fra arrayet (som er en funktion) og kalde den.
Now why do all such functions show the same value, `10`?
Men, hvorfor viser alle sådanne funktioner så samme værdi, `10`?
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.
Det skyldes, at der ikke er en lokal variabel `i` inde i `shooter`-funktionerne. Når en sådan funktion kaldes, tager den `i` fra dens ydre leksikale miljø. Så hvad er værdien af `i` når funktionen kaldes?
Then, what will be the value of `i`?
If we look at the source:
Kig på koden:
```js
function makeArmy() {
...
let i = 0;
while (i < 10) {
let shooter = function() { // shooter function
alert( i ); // should show its number
let shooter = function() { // shooter funktion
alert( i ); // skal vise sit nummer
};
shooters.push(shooter); // add function to the array
shooters.push(shooter); // tilføj funktionen til arrayet
i++;
}
...
}
```
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`).
Vi kan se at alle `shooter` funktioner er oprettet i det leksikale miljø af `makeArmy()` funktionen. Men når `army[5]()` kaldes, har `makeArmy` allerede afsluttet sin job, og den endelige værdi af `i` er `10` (`while` stopper ved `i=10`).
As the result, all `shooter` functions get the same value from the outer lexical environment and that is, the last value, `i=10`.
Som resultat får alle `shooter` funktioner samme værdi fra det ydre leksikale miljø og det er den sidste værdi, `i=10`.

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:
Som du kan se ovenfor så oprettes der et nyt leksikalt miljø ved hver iteration af `while {...}` blokken. Så for at fikse dette, kan vi kopiere værdien af `i` til en variabel inden i `while {...}` blokken, som dette:
```js run
function makeArmy() {
Expand All
@@ -69,8 +67,8 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco
*!*
let j = i;
*/!*
let shooter = function() { // shooter function
alert( *!*j*/!* ); // should show its number
let shooter = function() { // shooter funktion
alert( *!*j*/!* ); // skal vise sit nummer
};
shooters.push(shooter);
i++;
Expand All
@@ -81,18 +79,18 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco
let army = makeArmy();
// Now the code works correctly
// Nu virker koden som den skal
army[0](); // 0
army[5](); // 5
```
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.
Her vil `let j = i` deklarere en lokal variabel `j` og kopiere `i` over i den. Primitiver kopieres "ved deres værdi", så vi får en reelt uafhængig kopi af `i`, der tilhører den aktuelle løkkes iteration.
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 to the current loop iteration:
Shooters virker korrekt nu fordi værdien af `i` nu lever et lidt tættere på. Ikke i `makeArmy()` Lexical Environment, men i det Lexical Environment der svarer til den aktuelle løkkes iteration:

Such a problem could also be avoided if we used `for` in the beginning, like this:
Dette problem kunne undgås hvis vi brugte `for` i stedet for `while`, som dette:
```js run demo
function makeArmy() {
Expand All
@@ -102,8 +100,8 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco
*!*
for(let i = 0; i < 10; i++) {
*/!*
let shooter = function() { // shooter function
alert( i ); // should show its number
let shooter = function() { // shooter funktion
alert( i ); // bør vise sit nummer
};
shooters.push(shooter);
}
Expand All
@@ -117,13 +115,12 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco
army[5](); // 5
```
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.
Det er grundlæggende det samme fordi `for` gennem hver iteration genererer en ny leksikale miljø med sin egen variabel `i`. Så `shooter` genereret i hver iteration refererer til dens egen `i`, fra den pågældende iteration.

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?
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.
Nu, efter du har lagt så meget energi i at læse dette, og den endelige opskrift er så enkel - bare brug `for`, kan du måske tænke -- var det værd det?
Besides, there are indeed cases when one prefers `while` to `for`, and other scenarios, where such problems are real.
Vel, hvis du kunne svare spørgsmålet nemt, ville du ikke have læst løsningen. Så håber jeg, at denne opgave har hjulpet dig med at forstå tingene lidt bedre.
Desuden er der faktisk tilfælde hvor man hellere foretrækker `while` frem for `for`, og andre scenarier hvor sådanne problemer opstår.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The `work()` function in the code below gets `name` from the place of its origin through the outer lexical environment reference:
Funktionen `work()` i koden nedenfor får `name` fra stedet hvor den blev oprettet gennem referencen til det ydre leksikale miljø:

So, the result is `"Pete"` here.
Så resultatet er `"Pete"` her.
But if there were no `let name` in `makeWorker()`, then the search would go outside and take the global variable as we can see from the chain above. In that case the result would be `"John"`.
Men, hvis der ikke var `let name` i `makeWorker()`, så ville søgningen gå udenfor og tage den globale variabel som vi kan se fra kæden ovenfor. I det tilfælde ville resultatet være `"John"`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Variable scope, closure #247
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Variable scope, closure #247
Filter by extension
Viewed files
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There are no files selected for viewing
Uh oh!
There was an error while loading. Please reload this page.