Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Variable scope, closure#165

New issue

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
otmon76 merged 1 commit intojavascript-tutorial:masterfromotmon76:1.6.3
Jun 3, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
The answer is: **Pete**.
Odpověď zní: **Petr**.

A function gets outer variables as they are now, it uses the most recent values.
Funkce načítá vnější proměnné tak, jak vypadají právě v tuto chvíli. Používá poslední hodnoty.

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.
Staré hodnoty proměnných se nikam neukládají. Když funkce chce proměnnou, vezme její aktuální hodnotu ze svého vlastního lexikálního prostředí nebo z vnějšího.
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,22 +2,22 @@ importance: 5

---

#Does a function pickup latest changes?
#Odrážejí se ve funkci poslední změny?

The function sayHi uses an external variable name. When the function runs, which value is it going to use?
Funkce `řekniAhoj` využívá název externí proměnné. Když bude spuštěna, kterou hodnotu použije?

```js
letname = "John";
letjméno = "Jan";

functionsayHi() {
alert("Hi, " +name);
functionřekniAhoj() {
alert("Ahoj, " +jméno);
}

name = "Pete";
jméno = "Petr";

sayHi(); //what will it show: "John" or "Pete"?
řekniAhoj(); //co zobrazí: "Jan" nebo "Petr"?
```

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.
Takové situace jsou běžné při vývoji v prohlížeči i na straně serveru. Funkce může být navržena ke spuštění později, než byla vytvořena, například po uživatelské akci nebo síťovém požadavku.

So, the question is: does it pick up the latest changes?
Otázka tedy zní: odráží poslední změny?
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
functionmakeArmy() {
functionvytvořArmádu() {

letshooters = [];
letstřelci = [];

for(let i = 0; i < 10; i++) {
letshooter = function() { //shooter function
alert( i ); //should show its number
letstřelec = function() { //funkce střelec
alert( i );//by měla zobrazit své číslo
};
shooters.push(shooter);
střelci.push(střelec);
}

returnshooters;
returnstřelci;
}
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
functionmakeArmy() {
letshooters = [];
functionvytvořArmádu() {
letstřelci = [];

let i = 0;
while (i < 10) {
letshooter = function() { //shooter function
alert( i ); //should show its number
letstřelec = function() { //funkce střelec
alert( i );//by měla zobrazit své číslo
};
shooters.push(shooter);
střelci.push(střelec);
i++;
}

returnshooters;
returnstřelci;
}

/*
letarmy =makeArmy();
letarmáda =vytvořArmádu();

army[0](); //the shooter number 0 shows 10
army[5](); //and number 5also outputs 10...
// ...all shooters show 10instead of their 0, 1, 2, 3...
armáda[0](); //střelec číslo 0 zobrazí 10
armáda[5](); //a číslo 5zobrazí také 10...
// ...všichni střelci zobrazí 10místo svého čísla 0, 1, 2, 3...
*/
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
describe("army", function() {
describe("armáda", function() {

letarmy;
letarmáda;

before(function() {
army =makeArmy();
armáda =vytvořArmádu();
window.alert = sinon.stub(window, "alert");
});

it("army[0]shows 0", function() {
army[0]();
it("armáda[0]zobrazí 0", function() {
armáda[0]();
assert(alert.calledWith(0));
});


it("army[5]shows 5", function() {
army[5]();
it("armáda[5]zobrazí 5", function() {
armáda[5]();
assert(alert.calledWith(5));
});

Expand Down
91 changes: 45 additions & 46 deletions1-js/06-advanced-functions/03-closure/10-make-army/solution.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@

Let's examine what exactly happens inside `makeArmy`,and the solution will become obvious.
Prozkoumejme, co přesně se děje uvnitř funkce `vytvořArmádu`,a řešení bude zřejmé.

1.It creates an empty array `shooters`:
1.Vytvoří se prázdné pole `střelci`:

```js
letshooters = [];
letstřelci = [];
```
2.Fills it with functions via `shooters.push(function)` in the loop.
2.V cyklu se naplní funkcemi pomocí `střelci.push(function)`.

Every element is a function, so the resulting array looks like this:
Každý prvek je funkce, takže výsledné pole vypadá takto:

```js no-beautify
shooters = [
střelci = [
function () { alert(i); },
function () { alert(i); },
function () { alert(i); },
Expand All@@ -25,105 +25,104 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco
];
```

3.The array is returned from the function.
3.Toto pole funkce vrátí.

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.
Pak později volání kteréhokoli jeho prvku, např. `armáda[5]()`, načte z pole prvek `armáda[5]`(což je funkce) a zavolá jej.

Now why do all such functions show the same value, `10`?
Proč nyní všechny tyto funkce zobrazí stejnou hodnotu, `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.
Je to proto, že uvnitř funkcí `střelec` neexistuje žádná lokální proměnná `i`. Když je taková funkce volána, převezme`i`z vnějšího lexikálního prostředí.

Then, what will be the value of `i`?
Jaká pak bude hodnota proměnné `i`?

If we look at the source:
Když se podíváme na zdrojový kód:

```js
functionmakeArmy() {
functionvytvořArmádu() {
...
let i = 0;
while (i < 10) {
letshooter = function() { //shooter function
alert( i ); //should show its number
letstřelec = function() { //funkce střelec
alert( i );//by měla zobrazit své číslo
};
shooters.push(shooter); //add function to the array
střelci.push(střelec); //přidá funkci do pole
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`).
Vidíme, že všechny funkce `střelec` jsou vytvořeny v lexikálním prostředí funkce `vytvořArmádu()`. Když je však volána `armáda[5]()`, funkce `vytvořArmádu` již ukončila svou práci a poslední hodnota`i`je `10` (`while`se zastaví na `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`.
Výsledkem je, že všechny funkce `střelec` převezmou z vnějšího lexikálního prostředí stejnou hodnotu a tou bude poslední hodnota, `i=10`.

![](lexenv-makearmy-empty.svg)

As you can see above, on each iteration of a`while {...}`block, a new lexical environment is created. So, tofix this, we can copy the value of`i`into a variable within the`while {...}`block, like this:
Jak vidíte výše, při každé iteraci bloku`while {...}`bude vytvořeno nové lexikální prostředí. Abychom toopravili, můžeme zkopírovat hodnotu`i`do proměnné uvnitř bloku`while {...}`třeba takto:

```js run
functionmakeArmy() {
letshooters = [];
functionvytvořArmádu() {
letstřelci = [];

let i = 0;
while (i < 10) {
*!*
let j = i;
*/!*
letshooter = function() { //shooter function
alert( *!*j*/!* ); //should show its number
letstřelec = function() { //funkce střelec
alert( *!*j*/!* );//by měla zobrazit své číslo
};
shooters.push(shooter);
střelci.push(střelec);
i++;
}

returnshooters;
returnstřelci;
}

letarmy =makeArmy();
letarmáda =vytvořArmádu();

//Now the code works correctly
army[0](); // 0
army[5](); // 5
//Nyní kód funguje správně
armáda[0](); // 0
armáda[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.
Zde `let j = i`deklaruje „iteračně lokální“ proměnnou `j`a zkopíruje do ní`i`. Primitivy se kopírují „hodnotou“, takže ve skutečnosti získáme nezávislou kopii`i`,která patří do aktuální iterace cyklu.

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:
Střelci budou fungovat správně, protože hodnota`i`nyní existuje trochu blíže. Není v lexikálním prostředí funkce `vytvořArmádu()`, ale v lexikálním prostředí, které odpovídá aktuální iteraci cyklu:

![](lexenv-makearmy-while-fixed.svg)

Such a problem could also be avoided if we used`for` in the beginning, like this:
Tomuto problému se lze vyhnout i tak, že na začátku použijeme`for`, třeba takto:

```js run demo
functionmakeArmy() {
functionvytvořArmádu() {

letshooters = [];
letstřelci = [];

*!*
for(let i = 0; i < 10; i++) {
*/!*
letshooter = function() { //shooter function
alert( i ); //should show its number
letstřelec = function() { //funkce střelec
alert( i );//by měla zobrazit své číslo
};
shooters.push(shooter);
střelci.push(střelec);
}

returnshooters;
returnstřelci;
}

letarmy =makeArmy();
letarmáda =vytvořArmádu();

army[0](); // 0
army[5](); // 5
armáda[0](); // 0
armáda[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.
To je v zásadě totéž, protože `for`při každé své iteraci vygeneruje nové lexikální prostředí se svou vlastní proměnnou `i`.Takže `střelec` generovaný v každé iteraci odkazuje na své vlastní`i` přímo z této iterace.

![](lexenv-makearmy-for-fixed.svg)

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?
Když jste vložili tolik námahy do přečtení tohoto řešení a konečný recept je tak jednoduchý -- prostě použijeme `for`,můžete se divit --mělo to cenu?

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.

Besides, there are indeed cases when one prefers `while` to `for`, and other scenarios, where such problems are real.
Inu, kdybyste na tuto otázku dokázali snadno odpovědět, nečetli byste řešení. Snad vám tedy tato úloha pomohla trochu lépe všemu porozumět.

Kromě toho zajisté existují případy, kdy člověk dává přednost `while` před `for`, i jiné scénáře, v nichž takové problémy opravdu nastanou.
35 changes: 17 additions & 18 deletions1-js/06-advanced-functions/03-closure/10-make-army/task.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,40 +2,39 @@ importance: 5

---

#Army of functions
#Armáda funkcí

The following code creates an array of `shooters`.
Následující kód vytvoří pole `střelci`.

Every function is meant to output its number. But something is wrong...
Každá funkce má vypsat své číslo. Ale něco je špatně...

```js run
functionmakeArmy() {
letshooters = [];
functionvytvořArmádu() {
letstřelci = [];

let i = 0;
while (i < 10) {
letshooter = function() { //create a shooter function,
alert( i ); //that should show its number
letstřelec = function() { //vytvoříme funkci střelec,
alert( i );//která by měla zobrazit své číslo
};
shooters.push(shooter); //and add it to the array
střelci.push(střelec); //a přidáme ji do pole
i++;
}

// ...and return the array of shooters
returnshooters;
// ...a vrátíme pole střelci
returnstřelci;
}

letarmy =makeArmy();
letarmáda =vytvořArmádu();

*!*
//all shooters show 10instead of their numbers 0, 1, 2, 3...
army[0](); // 10from the shooter number 0
army[1](); // 10from the shooter number 1
army[2](); // 10 ...and so on.
//všichni střelci zobrazí 10místo svých čísel 0, 1, 2, 3...
armáda[0](); // 10od střelce číslo 0
armáda[1](); // 10od střelce číslo 1
armáda[2](); // 10 ...a tak dále.
*/!*
```

Why do all of the shooters show the same value?

Fix the code so that they work as intended.
Proč všichni střelci zobrazují stejnou hodnotu?

Opravte kód, aby fungoval tak, jak je zamýšleno.
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
The answer is: **Pete**.
Odpověď zní: **Petr**.

The `work()`function in the code below gets `name` from the place of its origin through the outer lexical environment reference:
Funkce `pracuj()`uvedená v následujícím kódu načte `jméno` z místa svého vzniku odkazem na vnější lexikální prostředí:

![](lexenv-nested-work.svg)

So, the result is `"Pete"` here.
Výsledkem zde je tedy `"Petr"`.

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"`.
Kdyby však ve funkci `vytvořPracovníka()` nebylo `let jméno`,pak by hledání pokračovalo dál ven a převzalo globální proměnnou, jak vidíme v uvedeném řetězci. V tom případě by výsledek byl `"Jan"`.
Loading

[8]ページ先頭

©2009-2025 Movatter.jp