Skip to content

Restructure the Solution for 'Army of Functions' task and Fix Typos #2081

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 10, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion 1-js/02-first-steps/08-operators/4-fix-prompt/solution.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ let b = "2"; // prompt("Second number?", 2);
alert(a + b); // 12
```

What we should to is to convert strings to numbers before `+`. For example, using `Number()` or prepending them with `+`.
What we should do is to convert strings to numbers before `+`. For example, using `Number()` or
prepending them with `+`.

For example, right before `prompt`:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ do {
The loop `do..while` repeats while both checks are truthy:

1. The check for `num <= 100` -- that is, the entered value is still not greater than `100`.
2. The check `&& num` is false when `num` is `null` or a empty string. Then the `while` loop stops too.
2. The check `&& num` is false when `num` is `null` or an empty string. Then the `while` loop stops too.

P.S. If `num` is `null` then `num <= 100` is `true`, so without the 2nd check the loop wouldn't stop if the user clicks CANCEL. Both checks are required.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function makeUser() {
name: "John",
ref: this
};
};
}

let user = makeUser();

Expand Down Expand Up @@ -45,7 +45,7 @@ function makeUser() {
}
*/!*
};
};
}

let user = makeUser();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function makeUser() {
name: "John",
ref: this
};
};
}

let user = makeUser();

Expand Down
57 changes: 28 additions & 29 deletions 1-js/06-advanced-functions/03-closure/10-make-army/solution.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ Let's examine what's done inside `makeArmy`, and the solution will become obviou

Then, later, the call to `army[5]()` will get the element `army[5]` from the array (it will be a function) and call it.

Now why all such functions show the same?
Now why do all such functions show the same value, `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.
That's because there's no local variable `i` inside `shooter` functions and neither in the code block of `while {...}`. When such a function is called, it takes `i` from its outer lexical environment.

What will be the value of `i`?

Expand All @@ -51,24 +51,29 @@ function makeArmy() {
}
```

...We can see that it lives in the lexical environment associated with the current `makeArmy()` run. But when `army[5]()` is called, `makeArmy` has already finished its job, and `i` has the last value: `10` (the end of `while`).
We can see that it lives in the lexical environment associated with the current `makeArmy()` run. But when `army[5]()` is called, `makeArmy` has already finished its job, and the final value of `i` is `10` (at the end of `while`).

As a result, all `shooter` functions get from the outer lexical envrironment the same, last value `i=10`.
As a result, all `shooter` functions get the same value from the outer lexical environment and that is, the last value, `i=10`.

We can fix it by moving the variable definition into the loop:
![](task-while-lexenv-makearmy.svg)

```js run demo
function makeArmy() {
As you can see above, on each iteration of a `while {...} ` block, a new lexical environment is created. This implies that as long as we store the value of `i` in a variable in the `while {...}` block, created Lexical Environment will have that variable with value of `i`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second phrase is hard to understand.

Copy link
Contributor Author

@MuhammedZakir MuhammedZakir Sep 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

created Lexical Environment will have that variable with value of i.

^This?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implies that as long as we store the value of i in a variable in the while {...} block, created Lexical Environment will have that variable with value of i.

Copy link
Contributor Author

@MuhammedZakir MuhammedZakir Sep 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the entire sentence not making any sense or is it the way it is phrased? Do you have any idea how to simplify it? I couldn't think of anything atm. :-(

P.S. I think people can grasp the meaning if it is read along with the snippet below.



```js run
function makeArmy() {
let shooters = [];

*!*
for(let i = 0; i < 10; i++) {
*/!*
let shooter = function() { // shooter function
alert( i ); // should show its number
};
let i = 0;
while (i < 10) {
*!*
let j = i;
*/!*
let shooter = function() { // shooter function
alert( *!*j*/!* ); // should show its number
};
shooters.push(shooter);
i++;
}

return shooters;
Expand All @@ -80,30 +85,22 @@ army[0](); // 0
army[5](); // 5
```

Now it works correctly, because every time the code block in `for (let i=0...) {...}` is executed, a new Lexical Environment is created for it, with the corresponding variable `i`.

So, 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. That's why now it works.

![](lexenv-makearmy.svg)

Here we rewrote `while` into `for`.
Here `let j = i` makes a loop body local `j` and copies the value of `i` to it. Primitives are copied "by value", so we actually get a complete independent copy of `i`, belonging to the current loop iteration.

Another trick could be possible, let's see it for better understanding of the subject:
In `for` loop, this is written as:

```js run
```js run demo
function makeArmy() {

let shooters = [];

let i = 0;
while (i < 10) {
*!*
let j = i;
for(let i = 0; i < 10; i++) {
*/!*
let shooter = function() { // shooter function
alert( *!*j*/!* ); // should show its number
alert( i ); // should show its number
};
shooters.push(shooter);
i++;
}

return shooters;
Expand All @@ -115,6 +112,8 @@ army[0](); // 0
army[5](); // 5
```

The `while` loop, just like `for`, makes a new Lexical Environment for each run. So here we make sure that it gets the right value for a `shooter`.
In this case, on each iteration, a new lexical environment is created for it, with variable i and its current value.

So, 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.

We copy `let j = i`. This makes a loop body local `j` and copies the value of `i` to it. Primitives are copied "by value", so we actually get a complete independent copy of `i`, belonging to the current loop iteration.
![](for-solution-lexenv-makearmy.svg)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions 1-js/06-advanced-functions/03-closure/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ When on an interview, a frontend developer gets a question about "what's a closu

Usually, a Lexical Environment is removed from memory with all the variables after the function call finishes. That's because there are no references to it. As any JavaScript object, it's only kept in memory while it's reachable.

...But if there's a nested function that is still reachable after the end of a function, then it has `[[Environment]]` property that references the lexical environment.
However, if there's a nested function that is still reachable after the end of a function, then it has `[[Environment]]` property that references the lexical environment.

In that case the Lexical Environment is still reachable even after the completion of the function, so it stays alive.

Expand All @@ -333,7 +333,7 @@ let g = f(); // g.[[Environment]] stores a reference to the Lexical Environment
// of the corresponding f() call
```

Please note that if `f()` is called many times, and resulting functions are saved, then all corresponding Lexical Environment objects will also be retained in memory. All 3 of them in the code below:
Please note that if `f()` is called many times, and resulting functions are saved, then all corresponding Lexical Environment objects will also be retained in memory. In the code below, all 3 of them:

```js
function f() {
Expand Down Expand Up @@ -415,4 +415,4 @@ g();

This feature of V8 is good to know. If you are debugging with Chrome/Opera, sooner or later you will meet it.

That is not a bug in the debugger, but rather a special feature of V8. Perhaps it will be changed sometime. You always can check for it by running the examples on this page.
That is not a bug in the debugger, but rather a special feature of V8. Perhaps it will be changed sometime. You can always check for it by running the examples on this page.