diff --git a/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md b/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md index 04f73fbd0b..14abfef608 100644 --- a/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md +++ b/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md @@ -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`: diff --git a/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md index 2e04a78c43..c7de5f09b0 100644 --- a/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md +++ b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md @@ -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. diff --git a/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md b/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md index c1aaf4f973..f33c9310ee 100644 --- a/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md +++ b/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md @@ -7,7 +7,7 @@ function makeUser() { name: "John", ref: this }; -}; +} let user = makeUser(); @@ -45,7 +45,7 @@ function makeUser() { } */!* }; -}; +} let user = makeUser(); diff --git a/1-js/04-object-basics/04-object-methods/4-object-property-this/task.md b/1-js/04-object-basics/04-object-methods/4-object-property-this/task.md index 4784b082c0..c6f8f96583 100644 --- a/1-js/04-object-basics/04-object-methods/4-object-property-this/task.md +++ b/1-js/04-object-basics/04-object-methods/4-object-property-this/task.md @@ -14,7 +14,7 @@ function makeUser() { name: "John", ref: this }; -}; +} let user = makeUser(); diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/lexenv-makearmy.svg b/1-js/06-advanced-functions/03-closure/10-make-army/for-solution-lexenv-makearmy.svg similarity index 100% rename from 1-js/06-advanced-functions/03-closure/10-make-army/lexenv-makearmy.svg rename to 1-js/06-advanced-functions/03-closure/10-make-army/for-solution-lexenv-makearmy.svg diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/solution.md b/1-js/06-advanced-functions/03-closure/10-make-army/solution.md index 0fb0b4a49a..0e4b729f8b 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/solution.md +++ b/1-js/06-advanced-functions/03-closure/10-make-army/solution.md @@ -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`? @@ -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`. + +```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; @@ -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; @@ -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) diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/task-while-lexenv-makearmy.svg b/1-js/06-advanced-functions/03-closure/10-make-army/task-while-lexenv-makearmy.svg new file mode 100644 index 0000000000..28027287de --- /dev/null +++ b/1-js/06-advanced-functions/03-closure/10-make-army/task-while-lexenv-makearmy.svg @@ -0,0 +1,87 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + outer + + + + + + + <empty> + + + + + + + <empty> + + + + + + + <empty> + + + + + + + <empty> + + makeArmy()LexicalEnvironment + while blockLexicalEnvironment + + + i: 10 + + + + diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md index 4d06c9db7f..5457d20312 100644 --- a/1-js/06-advanced-functions/03-closure/article.md +++ b/1-js/06-advanced-functions/03-closure/article.md @@ -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. @@ -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() { @@ -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.