diff --git a/1-js/01-getting-started/1-intro/limitations.png b/1-js/01-getting-started/1-intro/limitations.png index 4063bbcf2..a07b99030 100644 Binary files a/1-js/01-getting-started/1-intro/limitations.png and b/1-js/01-getting-started/1-intro/limitations.png differ diff --git a/1-js/01-getting-started/1-intro/limitations@2x.png b/1-js/01-getting-started/1-intro/limitations@2x.png index 55c030ef3..287b06d94 100644 Binary files a/1-js/01-getting-started/1-intro/limitations@2x.png and b/1-js/01-getting-started/1-intro/limitations@2x.png differ diff --git a/1-js/02-first-steps/02-structure/article.md b/1-js/02-first-steps/02-structure/article.md index 8f8eb86ad..6fe7041ee 100644 --- a/1-js/02-first-steps/02-structure/article.md +++ b/1-js/02-first-steps/02-structure/article.md @@ -6,7 +6,7 @@ The first thing we'll study is the building blocks of code. Statements are syntax constructs and commands that perform actions. -We've already seen a statement, `alert('Hello, world!')`, which shows the message "Hello world!". +We've already seen a statement, `alert('Hello, world!')`, which shows the message "Hello, world!". We can have as many statements in our code as we want. Statements can be separated with a semicolon. diff --git a/1-js/02-first-steps/04-variables/variable-change.png b/1-js/02-first-steps/04-variables/variable-change.png index 6dd3803d9..2aff675fe 100644 Binary files a/1-js/02-first-steps/04-variables/variable-change.png and b/1-js/02-first-steps/04-variables/variable-change.png differ diff --git a/1-js/02-first-steps/04-variables/variable-change@2x.png b/1-js/02-first-steps/04-variables/variable-change@2x.png index f57b04ab1..e74094c9d 100644 Binary files a/1-js/02-first-steps/04-variables/variable-change@2x.png and b/1-js/02-first-steps/04-variables/variable-change@2x.png differ diff --git a/1-js/02-first-steps/04-variables/variable.png b/1-js/02-first-steps/04-variables/variable.png index ab532d91d..3a4baaf42 100644 Binary files a/1-js/02-first-steps/04-variables/variable.png and b/1-js/02-first-steps/04-variables/variable.png differ diff --git a/1-js/02-first-steps/04-variables/variable@2x.png b/1-js/02-first-steps/04-variables/variable@2x.png index c9c37f034..35e9f454d 100644 Binary files a/1-js/02-first-steps/04-variables/variable@2x.png and b/1-js/02-first-steps/04-variables/variable@2x.png differ diff --git a/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.png b/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.png index 8c57b1885..37c5d5fb7 100644 Binary files a/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.png and b/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2.png differ diff --git a/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2@2x.png b/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2@2x.png index cbb2c611a..924a22a89 100644 Binary files a/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2@2x.png and b/1-js/02-first-steps/10-ifelse/2-check-standard/ifelse_task2@2x.png differ diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.png b/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.png index 8b54dc83d..0d5eb48fa 100644 Binary files a/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.png and b/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task.png differ diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task@2x.png b/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task@2x.png index 92001dfe8..14a06e93f 100644 Binary files a/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task@2x.png and b/1-js/02-first-steps/11-logical-operators/9-check-login/ifelse_task@2x.png differ diff --git a/1-js/02-first-steps/13-switch/article.md b/1-js/02-first-steps/13-switch/article.md index ae1149230..908570dd5 100644 --- a/1-js/02-first-steps/13-switch/article.md +++ b/1-js/02-first-steps/13-switch/article.md @@ -148,7 +148,7 @@ Let's emphasize that the equality check is always strict. The values must be of For example, let's consider the code: ```js run -let arg = prompt("Enter a value?") +let arg = prompt("Enter a value?"); switch (arg) { case '0': case '1': diff --git a/1-js/02-first-steps/14-function-basics/article.md b/1-js/02-first-steps/14-function-basics/article.md index 26e8e77c4..874890ab5 100644 --- a/1-js/02-first-steps/14-function-basics/article.md +++ b/1-js/02-first-steps/14-function-basics/article.md @@ -128,7 +128,7 @@ Variables declared outside of any function, such as the outer `userName` in the Global variables are visible from any function (unless shadowed by locals). -Usually, a function declares all variables specific to its task. Global variables only store project-level data, so when it's important that these variables are accesible from anywhere. Modern code has few or no globals. Most variables reside in their functions. +Usually, a function declares all variables specific to its task. Global variables only store project-level data, and it's important that these variables are accessible from anywhere. Modern code has few or no globals. Most variables reside in their functions. ``` ## Parameters diff --git a/1-js/02-first-steps/14-function-basics/function_basics.png b/1-js/02-first-steps/14-function-basics/function_basics.png index 5f3505811..a558b31a3 100644 Binary files a/1-js/02-first-steps/14-function-basics/function_basics.png and b/1-js/02-first-steps/14-function-basics/function_basics.png differ diff --git a/1-js/02-first-steps/14-function-basics/function_basics@2x.png b/1-js/02-first-steps/14-function-basics/function_basics@2x.png index e2fe5bac0..4d64f9852 100644 Binary files a/1-js/02-first-steps/14-function-basics/function_basics@2x.png and b/1-js/02-first-steps/14-function-basics/function_basics@2x.png differ diff --git a/1-js/03-code-quality/02-coding-style/code-style.png b/1-js/03-code-quality/02-coding-style/code-style.png index a9ae4b98e..8c457f5e2 100644 Binary files a/1-js/03-code-quality/02-coding-style/code-style.png and b/1-js/03-code-quality/02-coding-style/code-style.png differ diff --git a/1-js/03-code-quality/02-coding-style/code-style@2x.png b/1-js/03-code-quality/02-coding-style/code-style@2x.png index be9b99dc2..6789e6f63 100644 Binary files a/1-js/03-code-quality/02-coding-style/code-style@2x.png and b/1-js/03-code-quality/02-coding-style/code-style@2x.png differ diff --git a/1-js/03-code-quality/02-coding-style/figure-bracket-style.png b/1-js/03-code-quality/02-coding-style/figure-bracket-style.png index 112c2803e..9800b1c4a 100644 Binary files a/1-js/03-code-quality/02-coding-style/figure-bracket-style.png and b/1-js/03-code-quality/02-coding-style/figure-bracket-style.png differ diff --git a/1-js/03-code-quality/02-coding-style/figure-bracket-style@2x.png b/1-js/03-code-quality/02-coding-style/figure-bracket-style@2x.png index ce6e75c4d..8e917e9b3 100644 Binary files a/1-js/03-code-quality/02-coding-style/figure-bracket-style@2x.png and b/1-js/03-code-quality/02-coding-style/figure-bracket-style@2x.png differ diff --git a/1-js/03-code-quality/04-ninja-code/article.md b/1-js/03-code-quality/04-ninja-code/article.md index b34baf76a..9019242f2 100644 --- a/1-js/03-code-quality/04-ninja-code/article.md +++ b/1-js/03-code-quality/04-ninja-code/article.md @@ -83,7 +83,7 @@ While choosing a name try to use the most abstract word. Like `obj`, `data`, `va Give them a try. A young initiate may wonder -- are such names really useful for a ninja? Indeed, they are! - Sure, the variable name still means something. It says what's inside the variable: a string, a number or something else. But when an outsider tries to understand the code, he'll be surprised to see that there's actually no information at all! And will ultimately fail to alter your well-thought code. + Sure, the variable name still means something. It says what's inside the variable: a string, a number or something else. But when an outsider tries to understand the code, they'll be surprised to see that there's actually no information at all! And will ultimately fail to alter your well-thought code. The value type is easy to find out by debugging. But what's the meaning of the variable? Which string/number does it store? @@ -153,7 +153,7 @@ function ninjaFunction(elem) { } ``` -A fellow programmer who wants to work with `elem` in the second half of the function will be surprised... Only during the debugging, after examining the code they will find out that he's working with a clone! +A fellow programmer who wants to work with `elem` in the second half of the function will be surprised... Only during the debugging, after examining the code they will find out that they're working with a clone! Seen in code regularly. Deadly effective even against an experienced ninja. @@ -197,7 +197,7 @@ function render() { A programmer who jumps inside the `render` will probably fail to notice that there's a local `user` shadowing the outer one. -Then he'll try to work with `user` assuming that it's the external variable, the result of `authenticateUser()`... The trap is sprung! Hello, debugger... +Then they'll try to work with `user` assuming that it's the external variable, the result of `authenticateUser()`... The trap is sprung! Hello, debugger... ## Side-effects everywhere! diff --git a/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js b/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js index e7f63284f..db3283e49 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js +++ b/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js @@ -1,7 +1,7 @@ function isEmpty(obj) { for (let key in obj) { - // if the loop has started, there is a prorty + // if the loop has started, there is a property return false; } return true; -} \ No newline at end of file +} diff --git a/1-js/04-object-basics/01-object/3-is-empty/solution.md b/1-js/04-object-basics/01-object/3-is-empty/solution.md index b3f40e3d2..b876973b5 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/solution.md +++ b/1-js/04-object-basics/01-object/3-is-empty/solution.md @@ -1,10 +1 @@ Just loop over the object and `return false` immediately if there's at least one property. - -```js -function isEmpty(obj) { - for (let key in obj) { - return false; - } - return true; -} -``` diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/solution.md b/1-js/04-object-basics/01-object/8-multiply-numeric/solution.md index e7edda60d..e69de29bb 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/solution.md +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/solution.md @@ -1,19 +0,0 @@ -``` js run - -// before the call -let menu = { - width: 200, - height: 300, - title: "My menu" -}; - -function multiplyNumeric(obj) { - for (let key in obj) { - if (typeof obj[key] == 'number') { - obj[key] *= 2; - } - } -} - -alert(menu); -``` diff --git a/1-js/04-object-basics/01-object/variable-contains-reference.png b/1-js/04-object-basics/01-object/variable-contains-reference.png index d6e7fddff..c417ac1c1 100644 Binary files a/1-js/04-object-basics/01-object/variable-contains-reference.png and b/1-js/04-object-basics/01-object/variable-contains-reference.png differ diff --git a/1-js/04-object-basics/01-object/variable-contains-reference@2x.png b/1-js/04-object-basics/01-object/variable-contains-reference@2x.png index 145bad29a..0b877009d 100644 Binary files a/1-js/04-object-basics/01-object/variable-contains-reference@2x.png and b/1-js/04-object-basics/01-object/variable-contains-reference@2x.png differ diff --git a/1-js/04-object-basics/01-object/variable-copy-reference.png b/1-js/04-object-basics/01-object/variable-copy-reference.png index 97510c4b2..919a4f579 100644 Binary files a/1-js/04-object-basics/01-object/variable-copy-reference.png and b/1-js/04-object-basics/01-object/variable-copy-reference.png differ diff --git a/1-js/04-object-basics/01-object/variable-copy-reference@2x.png b/1-js/04-object-basics/01-object/variable-copy-reference@2x.png index a64238a52..7a35fb15f 100644 Binary files a/1-js/04-object-basics/01-object/variable-copy-reference@2x.png and b/1-js/04-object-basics/01-object/variable-copy-reference@2x.png differ diff --git a/1-js/04-object-basics/01-object/variable-copy-value.png b/1-js/04-object-basics/01-object/variable-copy-value.png index e21af0990..e5c330c39 100644 Binary files a/1-js/04-object-basics/01-object/variable-copy-value.png and b/1-js/04-object-basics/01-object/variable-copy-value.png differ diff --git a/1-js/04-object-basics/01-object/variable-copy-value@2x.png b/1-js/04-object-basics/01-object/variable-copy-value@2x.png index 2f0b2f47d..98edf5c8b 100644 Binary files a/1-js/04-object-basics/01-object/variable-copy-value@2x.png and b/1-js/04-object-basics/01-object/variable-copy-value@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/family-delete-refs.png b/1-js/04-object-basics/02-garbage-collection/family-delete-refs.png index 5c10f0e47..1447f15fa 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/family-delete-refs.png and b/1-js/04-object-basics/02-garbage-collection/family-delete-refs.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/family-delete-refs@2x.png b/1-js/04-object-basics/02-garbage-collection/family-delete-refs@2x.png index 24d29630e..67d95ba07 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/family-delete-refs@2x.png and b/1-js/04-object-basics/02-garbage-collection/family-delete-refs@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/family-no-family.png b/1-js/04-object-basics/02-garbage-collection/family-no-family.png index a4ce30a35..95844adca 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/family-no-family.png and b/1-js/04-object-basics/02-garbage-collection/family-no-family.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/family-no-family@2x.png b/1-js/04-object-basics/02-garbage-collection/family-no-family@2x.png index 0d9949839..40cc0e74a 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/family-no-family@2x.png and b/1-js/04-object-basics/02-garbage-collection/family-no-family@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/family-no-father-2.png b/1-js/04-object-basics/02-garbage-collection/family-no-father-2.png index e24dba5b5..63001b7a5 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/family-no-father-2.png and b/1-js/04-object-basics/02-garbage-collection/family-no-father-2.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/family-no-father-2@2x.png b/1-js/04-object-basics/02-garbage-collection/family-no-father-2@2x.png index a6c4ee36a..44cfdddb4 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/family-no-father-2@2x.png and b/1-js/04-object-basics/02-garbage-collection/family-no-father-2@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/family-no-father.png b/1-js/04-object-basics/02-garbage-collection/family-no-father.png index df14624bc..1038b7e47 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/family-no-father.png and b/1-js/04-object-basics/02-garbage-collection/family-no-father.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/family-no-father@2x.png b/1-js/04-object-basics/02-garbage-collection/family-no-father@2x.png index 5ab4b3792..f2b137651 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/family-no-father@2x.png and b/1-js/04-object-basics/02-garbage-collection/family-no-father@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/family.png b/1-js/04-object-basics/02-garbage-collection/family.png index dbbc01d2f..b2fec7060 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/family.png and b/1-js/04-object-basics/02-garbage-collection/family.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/family@2x.png b/1-js/04-object-basics/02-garbage-collection/family@2x.png index 64b4619ba..646355c96 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/family@2x.png and b/1-js/04-object-basics/02-garbage-collection/family@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-1.png b/1-js/04-object-basics/02-garbage-collection/garbage-collection-1.png index 423191778..501798a37 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/garbage-collection-1.png and b/1-js/04-object-basics/02-garbage-collection/garbage-collection-1.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-1@2x.png b/1-js/04-object-basics/02-garbage-collection/garbage-collection-1@2x.png index 223ea32a1..91114279c 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/garbage-collection-1@2x.png and b/1-js/04-object-basics/02-garbage-collection/garbage-collection-1@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-2.png b/1-js/04-object-basics/02-garbage-collection/garbage-collection-2.png index da63d3969..4d1cb84ac 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/garbage-collection-2.png and b/1-js/04-object-basics/02-garbage-collection/garbage-collection-2.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-2@2x.png b/1-js/04-object-basics/02-garbage-collection/garbage-collection-2@2x.png index 1f614e3e6..ca2db9ab8 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/garbage-collection-2@2x.png and b/1-js/04-object-basics/02-garbage-collection/garbage-collection-2@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-3.png b/1-js/04-object-basics/02-garbage-collection/garbage-collection-3.png index e77144c1d..e60b92c03 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/garbage-collection-3.png and b/1-js/04-object-basics/02-garbage-collection/garbage-collection-3.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-3@2x.png b/1-js/04-object-basics/02-garbage-collection/garbage-collection-3@2x.png index 37e349b62..c2e79d7b7 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/garbage-collection-3@2x.png and b/1-js/04-object-basics/02-garbage-collection/garbage-collection-3@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-4.png b/1-js/04-object-basics/02-garbage-collection/garbage-collection-4.png index 110e0d9c4..79c935c03 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/garbage-collection-4.png and b/1-js/04-object-basics/02-garbage-collection/garbage-collection-4.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-4@2x.png b/1-js/04-object-basics/02-garbage-collection/garbage-collection-4@2x.png index c09d75f9d..e3b040979 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/garbage-collection-4@2x.png and b/1-js/04-object-basics/02-garbage-collection/garbage-collection-4@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-5.png b/1-js/04-object-basics/02-garbage-collection/garbage-collection-5.png index bc4ea9670..28625adc6 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/garbage-collection-5.png and b/1-js/04-object-basics/02-garbage-collection/garbage-collection-5.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-5@2x.png b/1-js/04-object-basics/02-garbage-collection/garbage-collection-5@2x.png index 0ab697e68..af39f0cd7 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/garbage-collection-5@2x.png and b/1-js/04-object-basics/02-garbage-collection/garbage-collection-5@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/memory-user-john-admin.png b/1-js/04-object-basics/02-garbage-collection/memory-user-john-admin.png index 29c4fcbea..b19f99533 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/memory-user-john-admin.png and b/1-js/04-object-basics/02-garbage-collection/memory-user-john-admin.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/memory-user-john-admin@2x.png b/1-js/04-object-basics/02-garbage-collection/memory-user-john-admin@2x.png index 2f80f19a2..ffe907161 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/memory-user-john-admin@2x.png and b/1-js/04-object-basics/02-garbage-collection/memory-user-john-admin@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/memory-user-john-lost.png b/1-js/04-object-basics/02-garbage-collection/memory-user-john-lost.png index cdc1d4904..1a143778a 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/memory-user-john-lost.png and b/1-js/04-object-basics/02-garbage-collection/memory-user-john-lost.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/memory-user-john-lost@2x.png b/1-js/04-object-basics/02-garbage-collection/memory-user-john-lost@2x.png index d58afdb58..54a90a92d 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/memory-user-john-lost@2x.png and b/1-js/04-object-basics/02-garbage-collection/memory-user-john-lost@2x.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/memory-user-john.png b/1-js/04-object-basics/02-garbage-collection/memory-user-john.png index 3ba5730de..8ac34e215 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/memory-user-john.png and b/1-js/04-object-basics/02-garbage-collection/memory-user-john.png differ diff --git a/1-js/04-object-basics/02-garbage-collection/memory-user-john@2x.png b/1-js/04-object-basics/02-garbage-collection/memory-user-john@2x.png index 5aa81bb0c..5f0c87410 100644 Binary files a/1-js/04-object-basics/02-garbage-collection/memory-user-john@2x.png and b/1-js/04-object-basics/02-garbage-collection/memory-user-john@2x.png differ diff --git a/1-js/04-object-basics/04-object-methods/7-calculator/solution.md b/1-js/04-object-basics/04-object-methods/7-calculator/solution.md index 22c4bf187..459997624 100644 --- a/1-js/04-object-basics/04-object-methods/7-calculator/solution.md +++ b/1-js/04-object-basics/04-object-methods/7-calculator/solution.md @@ -1,6 +1,5 @@ - -```js run demo +```js run demo solution let calculator = { sum() { return this.a + this.b; @@ -20,4 +19,3 @@ calculator.read(); alert( calculator.sum() ); alert( calculator.mul() ); ``` - diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md b/1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md index 41edd7236..2b47873fc 100644 --- a/1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md +++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md @@ -1,6 +1,6 @@ The solution is to return the object itself from every call. -```js run +```js run demo let ladder = { step: 0, up() { @@ -28,7 +28,7 @@ ladder.up().up().down().up().down().showStep(); // 1 We also can write a single call per line. For long chains it's more readable: -```js +```js ladder .up() .up() @@ -37,4 +37,3 @@ ladder .down() .showStep(); // 1 ``` - diff --git a/1-js/04-object-basics/04-object-methods/article.md b/1-js/04-object-basics/04-object-methods/article.md index cdb44a6b0..5ef5b24e6 100644 --- a/1-js/04-object-basics/04-object-methods/article.md +++ b/1-js/04-object-basics/04-object-methods/article.md @@ -214,7 +214,7 @@ sayHi(); // undefined In this case `this` is `undefined` in strict mode. If we try to access `this.name`, there will be an error. -In non-strict mode (if one forgets `use strict`) the value of `this` in such case will be the *global object* (`window` in a browser, we'll get to it later). This is a historical behavior that `"use strict"` fixes. +In non-strict mode the value of `this` in such case will be the *global object* (`window` in a browser, we'll get to it later in the chapter [](info:global-object)). This is a historical behavior that `"use strict"` fixes. Please note that usually a call of a function that uses `this` without an object is not normal, but rather a programming mistake. If a function has `this`, then it is usually meant to be called in the context of an object. diff --git a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md index e5583c5d0..86bb65416 100644 --- a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md +++ b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md @@ -1,5 +1,3 @@ - - ```js run demo function Calculator() { diff --git a/1-js/05-data-types/03-string/3-truncate/solution.md b/1-js/05-data-types/03-string/3-truncate/solution.md index a49b70909..5546c47ee 100644 --- a/1-js/05-data-types/03-string/3-truncate/solution.md +++ b/1-js/05-data-types/03-string/3-truncate/solution.md @@ -2,10 +2,9 @@ The maximal length must be `maxlength`, so we need to cut it a little shorter, t Note that there is actually a single unicode character for an ellipsis. That's not three dots. -```js run +```js run demo function truncate(str, maxlength) { - return (str.length > maxlength) ? + return (str.length > maxlength) ? str.slice(0, maxlength - 1) + '…' : str; } ``` - diff --git a/1-js/05-data-types/03-string/4-extract-currency/solution.md b/1-js/05-data-types/03-string/4-extract-currency/solution.md index d9012677b..e69de29bb 100644 --- a/1-js/05-data-types/03-string/4-extract-currency/solution.md +++ b/1-js/05-data-types/03-string/4-extract-currency/solution.md @@ -1,5 +0,0 @@ -```js run - function extractCurrencyValue(str) { - return +str.slice(1); - } -``` diff --git a/1-js/05-data-types/04-array/10-maximal-subarray/solution.md b/1-js/05-data-types/04-array/10-maximal-subarray/solution.md index 3b82e6452..edf392894 100644 --- a/1-js/05-data-types/04-array/10-maximal-subarray/solution.md +++ b/1-js/05-data-types/04-array/10-maximal-subarray/solution.md @@ -1,4 +1,4 @@ -# The slow solution +# Slow solution We can calculate all possible subsums. @@ -67,7 +67,7 @@ Let's walk the array and keep the current partial sum of elements in the variabl If the description is too vague, please see the code, it's short enough: -```js run +```js run demo function getMaxSubSum(arr) { let maxSum = 0; let partialSum = 0; diff --git a/1-js/05-data-types/04-array/array-pop.png b/1-js/05-data-types/04-array/array-pop.png index 9113c76be..c4f80e851 100644 Binary files a/1-js/05-data-types/04-array/array-pop.png and b/1-js/05-data-types/04-array/array-pop.png differ diff --git a/1-js/05-data-types/04-array/array-pop@2x.png b/1-js/05-data-types/04-array/array-pop@2x.png index e6ec8d8fb..f7179bbc8 100644 Binary files a/1-js/05-data-types/04-array/array-pop@2x.png and b/1-js/05-data-types/04-array/array-pop@2x.png differ diff --git a/1-js/05-data-types/04-array/array-shift.png b/1-js/05-data-types/04-array/array-shift.png index 03b29d930..093b16ed9 100644 Binary files a/1-js/05-data-types/04-array/array-shift.png and b/1-js/05-data-types/04-array/array-shift.png differ diff --git a/1-js/05-data-types/04-array/array-shift@2x.png b/1-js/05-data-types/04-array/array-shift@2x.png index c9888a44c..3be433f74 100644 Binary files a/1-js/05-data-types/04-array/array-shift@2x.png and b/1-js/05-data-types/04-array/array-shift@2x.png differ diff --git a/1-js/05-data-types/04-array/array-speed.png b/1-js/05-data-types/04-array/array-speed.png index 3737e8248..f537417df 100644 Binary files a/1-js/05-data-types/04-array/array-speed.png and b/1-js/05-data-types/04-array/array-speed.png differ diff --git a/1-js/05-data-types/04-array/array-speed@2x.png b/1-js/05-data-types/04-array/array-speed@2x.png index e45624b50..49e36d63e 100644 Binary files a/1-js/05-data-types/04-array/array-speed@2x.png and b/1-js/05-data-types/04-array/array-speed@2x.png differ diff --git a/1-js/05-data-types/04-array/article.md b/1-js/05-data-types/04-array/article.md index 48138b632..2fad1601d 100644 --- a/1-js/05-data-types/04-array/article.md +++ b/1-js/05-data-types/04-array/article.md @@ -104,7 +104,7 @@ A [queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) is one of mo Arrays support both operations. -In practice we meet it very often. For example, a queue of messages that need to be shown on-screen. +In practice we need it very often. For example, a queue of messages that need to be shown on-screen. There's another use case for arrays -- the data structure named [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)). diff --git a/1-js/05-data-types/04-array/queue.png b/1-js/05-data-types/04-array/queue.png index 5e1fb640c..d2eb466a8 100644 Binary files a/1-js/05-data-types/04-array/queue.png and b/1-js/05-data-types/04-array/queue.png differ diff --git a/1-js/05-data-types/04-array/queue@2x.png b/1-js/05-data-types/04-array/queue@2x.png index 6acfc83d1..823afaa5f 100644 Binary files a/1-js/05-data-types/04-array/queue@2x.png and b/1-js/05-data-types/04-array/queue@2x.png differ diff --git a/1-js/05-data-types/04-array/stack.png b/1-js/05-data-types/04-array/stack.png index d1c9cb9af..6feb0c947 100644 Binary files a/1-js/05-data-types/04-array/stack.png and b/1-js/05-data-types/04-array/stack.png differ diff --git a/1-js/05-data-types/04-array/stack@2x.png b/1-js/05-data-types/04-array/stack@2x.png index b3835fa44..79f6f8d96 100644 Binary files a/1-js/05-data-types/04-array/stack@2x.png and b/1-js/05-data-types/04-array/stack@2x.png differ diff --git a/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js b/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js index 024d6d6c2..490f570ad 100644 --- a/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js @@ -1,8 +1,10 @@ function camelize(str) { return str - .split('-') // my-long-word -> ['my', 'long', 'word'] - .map( + .split('-') // splits 'my-long-word' into array ['my', 'long', 'word'] + .map( + // capitalizes first letters of all array items except the first one + // converts ['my', 'long', 'word'] into ['my', 'Long', 'Word'] (word, index) => index == 0 ? word : word[0].toUpperCase() + word.slice(1) - ) // ['my', 'long', 'word'] -> ['my', 'Long', 'Word'] - .join(''); // ['my', 'Long', 'Word'] -> myLongWord + ) + .join(''); // joins ['my', 'Long', 'Word'] into 'myLongWord' } diff --git a/1-js/05-data-types/05-array-methods/11-array-unique/solution.md b/1-js/05-data-types/05-array-methods/11-array-unique/solution.md index 8f7fd9af4..32d3b2679 100644 --- a/1-js/05-data-types/05-array-methods/11-array-unique/solution.md +++ b/1-js/05-data-types/05-array-methods/11-array-unique/solution.md @@ -2,7 +2,7 @@ Let's walk the array items: - For each item we'll check if the resulting array already has that item. - If it is so, then ignore, otherwise add to results. -```js run +```js run demo function unique(arr) { let result = []; diff --git a/1-js/05-data-types/05-array-methods/2-filter-range/solution.md b/1-js/05-data-types/05-array-methods/2-filter-range/solution.md index e69de29bb..73993a07a 100644 --- a/1-js/05-data-types/05-array-methods/2-filter-range/solution.md +++ b/1-js/05-data-types/05-array-methods/2-filter-range/solution.md @@ -0,0 +1,14 @@ +```js run demo +function filterRange(arr, a, b) { + // added brackets around the expression for better readability + return arr.filter(item => (a <= item && item <= b)); +} + +let arr = [5, 3, 8, 1]; + +let filtered = filterRange(arr, 1, 4); + +alert( filtered ); // 3,1 (matching values) + +alert( arr ); // 5,3,8,1 (not modified) +``` diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js index 61cda126b..488db3755 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js @@ -1,5 +1,4 @@ - function filterRangeInPlace(arr, a, b) { for (let i = 0; i < arr.length; i++) { @@ -12,4 +11,4 @@ function filterRangeInPlace(arr, a, b) { } } -} \ No newline at end of file +} diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md index e69de29bb..36e3130ff 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md @@ -0,0 +1,21 @@ +```js run demo +function filterRangeInPlace(arr, a, b) { + + for (let i = 0; i < arr.length; i++) { + let val = arr[i]; + + // remove if outside of the interval + if (val < a || val > b) { + arr.splice(i, 1); + i--; + } + } + +} + +let arr = [5, 3, 8, 1]; + +filterRangeInPlace(arr, 1, 4); // removed the numbers except from 1 to 4 + +alert( arr ); // [3, 1] +``` diff --git a/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md b/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md index ad4e790ce..f5684a6d5 100644 --- a/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md +++ b/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md @@ -1,6 +1,6 @@ ```js run no-beautify function sortByName(arr) { - arr.sort((a, b) => b.name > a.name ? 1 : -1); + arr.sort((a, b) => a.age > b.age ? 1 : -1); } let john = { name: "John", age: 25 }; @@ -12,6 +12,6 @@ let arr = [ john, pete, mary ]; sortByName(arr); // now sorted is: [john, mary, pete] -alert(arr[1].name); // Mary +alert(arr[0].name); // John +alert(arr[2].name); // Pete ``` - diff --git a/1-js/05-data-types/05-array-methods/8-sort-objects/task.md b/1-js/05-data-types/05-array-methods/8-sort-objects/task.md index 8a3f5a97a..498cf5bc2 100644 --- a/1-js/05-data-types/05-array-methods/8-sort-objects/task.md +++ b/1-js/05-data-types/05-array-methods/8-sort-objects/task.md @@ -4,7 +4,7 @@ importance: 5 # Sort objects -Write the function `sortByName(users)` that gets an array of objects with property `name` and sorts it. +Write the function `sortByName(users)` that gets an array of objects with the `age` property and sorts them by `age`. For instance: @@ -18,6 +18,6 @@ let arr = [ john, pete, mary ]; sortByName(arr); // now: [john, mary, pete] -alert(arr[1].name); // Mary +alert(arr[0].name); // Mary +alert(arr[2].name); // Pete ``` - diff --git a/1-js/05-data-types/05-array-methods/article.md b/1-js/05-data-types/05-array-methods/article.md index 77e62b823..42bbd9465 100644 --- a/1-js/05-data-types/05-array-methods/article.md +++ b/1-js/05-data-types/05-array-methods/article.md @@ -275,7 +275,8 @@ Here the [arr.find](mdn:js/Array/find) method comes in handy. The syntax is: ```js let result = arr.find(function(item, index, array) { - // should return true if the item is what we are looking for + // if true is returned, item is returned and iteration is stopped + // for falsy scenario returns undefined }); ``` @@ -313,11 +314,12 @@ The `find` method looks for a single (first) element that makes the function ret If there may be many, we can use [arr.filter(fn)](mdn:js/Array/filter). -The syntax is roughly the same as `find`, but it returns an array of matching elements: +The syntax is similar to `find`, but filter continues to iterate for all array elements even if `true` is already returned: ```js let results = arr.filter(function(item, index, array) { - // should return true if the item passes the filter + // if true item is pushed to results and iteration continues + // returns empty array for complete falsy scenario }); ``` @@ -568,7 +570,7 @@ The calculation flow: ![](reduce.png) -Or in the form of a table, where each row represents is a function call on the next array element: +Or in the form of a table, where each row represents a function call on the next array element: | |`sum`|`current`|`result`| |---|-----|---------|---------| diff --git a/1-js/05-data-types/05-array-methods/reduce.png b/1-js/05-data-types/05-array-methods/reduce.png index 41476d2ae..13d13536b 100644 Binary files a/1-js/05-data-types/05-array-methods/reduce.png and b/1-js/05-data-types/05-array-methods/reduce.png differ diff --git a/1-js/05-data-types/05-array-methods/reduce@2x.png b/1-js/05-data-types/05-array-methods/reduce@2x.png index f31647d17..5625c2b47 100644 Binary files a/1-js/05-data-types/05-array-methods/reduce@2x.png and b/1-js/05-data-types/05-array-methods/reduce@2x.png differ diff --git a/1-js/05-data-types/07-map-set-weakmap-weakset/02-filter-anagrams/solution.md b/1-js/05-data-types/07-map-set-weakmap-weakset/02-filter-anagrams/solution.md index 7ae86f4f3..4c8af1f24 100644 --- a/1-js/05-data-types/07-map-set-weakmap-weakset/02-filter-anagrams/solution.md +++ b/1-js/05-data-types/07-map-set-weakmap-weakset/02-filter-anagrams/solution.md @@ -59,7 +59,7 @@ Here we could also use a plain object instead of the `Map`, because keys are str That's how the solution can look: -```js run +```js run demo function aclean(arr) { let obj = {}; diff --git a/1-js/05-data-types/07-map-set-weakmap-weakset/03-iterable-keys/task.md b/1-js/05-data-types/07-map-set-weakmap-weakset/03-iterable-keys/task.md index 9a3e5d250..b1ccbd0ac 100644 --- a/1-js/05-data-types/07-map-set-weakmap-weakset/03-iterable-keys/task.md +++ b/1-js/05-data-types/07-map-set-weakmap-weakset/03-iterable-keys/task.md @@ -16,7 +16,7 @@ map.set("name", "John"); let keys = map.keys(); *!* -// Error: numbers.push is not a function +// Error: keys.push is not a function keys.push("more"); */!* ``` diff --git a/1-js/05-data-types/07-map-set-weakmap-weakset/article.md b/1-js/05-data-types/07-map-set-weakmap-weakset/article.md index ecbc08f95..927d60692 100644 --- a/1-js/05-data-types/07-map-set-weakmap-weakset/article.md +++ b/1-js/05-data-types/07-map-set-weakmap-weakset/article.md @@ -328,7 +328,7 @@ Compare it with the regular `Map` example above. Now if `john` only exists as th - `weakMap.get(key)` - `weakMap.set(key, value)` -- `weakMap.delete(key, value)` +- `weakMap.delete(key)` - `weakMap.has(key)` Why such a limitation? That's for technical reasons. If an object has lost all other references (like `john` in the code above), then it is to be garbage-collected automatically. But technically it's not exactly specified *when the cleanup happens*. diff --git a/1-js/05-data-types/08-keys-values-entries/01-sum-salaries/solution.md b/1-js/05-data-types/08-keys-values-entries/01-sum-salaries/solution.md index e69de29bb..27a7b418a 100644 --- a/1-js/05-data-types/08-keys-values-entries/01-sum-salaries/solution.md +++ b/1-js/05-data-types/08-keys-values-entries/01-sum-salaries/solution.md @@ -0,0 +1,29 @@ +```js run demo +function sumSalaries(salaries) { + + let sum = 0; + for (let salary of Object.values(salaries)) { + sum += salary; + } + + return sum; // 650 +} + +let salaries = { + "John": 100, + "Pete": 300, + "Mary": 250 +}; + +alert( sumSalaries(salaries) ); // 650 +``` +Or, optionally, we could also get the sum using `Object.values` and `reduce`: + +```js +// reduce loops over array of salaries, +// adding them up +// and returns the result +function sumSalaries(salaries) { + return Object.values(salaries).reduce((a, b) => a + b, 0) // 650 +} +``` diff --git a/1-js/05-data-types/09-destructuring-assignment/6-max-salary/_js.view/solution.js b/1-js/05-data-types/09-destructuring-assignment/6-max-salary/_js.view/solution.js index d95cf1b1e..f4bd5c761 100644 --- a/1-js/05-data-types/09-destructuring-assignment/6-max-salary/_js.view/solution.js +++ b/1-js/05-data-types/09-destructuring-assignment/6-max-salary/_js.view/solution.js @@ -3,7 +3,7 @@ function topSalary(salaries) { let max = 0; let maxName = null; - for(let [name, salary] of Object.entries(salaries)) { + for(const [name, salary] of Object.entries(salaries)) { if (max < salary) { max = salary; maxName = name; diff --git a/1-js/05-data-types/09-destructuring-assignment/article.md b/1-js/05-data-types/09-destructuring-assignment/article.md index 2e1960655..ff56c38e7 100644 --- a/1-js/05-data-types/09-destructuring-assignment/article.md +++ b/1-js/05-data-types/09-destructuring-assignment/article.md @@ -128,6 +128,7 @@ alert(name1); // Julius alert(name2); // Caesar *!* +// Note that type of `rest` is Array. alert(rest[0]); // Consul alert(rest[1]); // of the Roman Republic alert(rest.length); // 2 @@ -146,6 +147,7 @@ let [firstName, surname] = []; */!* alert(firstName); // undefined +alert(surname); // undefined ``` If we want a "default" value to replace the missing one, we can provide it using `=`: @@ -335,7 +337,7 @@ The problem is that JavaScript treats `{...}` in the main code flow (not inside } ``` -To show JavaScript that it's not a code block, we can wrap the whole assignment in brackets `(...)`: +To show JavaScript that it's not a code block, we can wrap the whole assignment in parentheses `(...)`: ```js run let title, width, height; @@ -383,6 +385,8 @@ alert(item2); // Donut The whole `options` object except `extra` that was not mentioned, is assigned to corresponding variables. +Note that `size` and `items` itself is not destructured. + ![](destructuring-complex.png) Finally, we have `width`, `height`, `item1`, `item2` and `title` from the default value. diff --git a/1-js/05-data-types/09-destructuring-assignment/destructuring-complex.png b/1-js/05-data-types/09-destructuring-assignment/destructuring-complex.png index 50c4ffc93..80daca3d4 100644 Binary files a/1-js/05-data-types/09-destructuring-assignment/destructuring-complex.png and b/1-js/05-data-types/09-destructuring-assignment/destructuring-complex.png differ diff --git a/1-js/05-data-types/09-destructuring-assignment/destructuring-complex@2x.png b/1-js/05-data-types/09-destructuring-assignment/destructuring-complex@2x.png index bb908281d..66982a9f9 100644 Binary files a/1-js/05-data-types/09-destructuring-assignment/destructuring-complex@2x.png and b/1-js/05-data-types/09-destructuring-assignment/destructuring-complex@2x.png differ diff --git a/1-js/05-data-types/10-date/2-get-week-day/solution.md b/1-js/05-data-types/10-date/2-get-week-day/solution.md index 2acaabf9c..58d75c1c3 100644 --- a/1-js/05-data-types/10-date/2-get-week-day/solution.md +++ b/1-js/05-data-types/10-date/2-get-week-day/solution.md @@ -2,7 +2,7 @@ The method `date.getDay()` returns the number of the weekday, starting from sund Let's make an array of weekdays, so that we can get the proper day name by its number: -```js run +```js run demo function getWeekDay(date) { let days = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']; diff --git a/1-js/05-data-types/10-date/3-weekday/solution.md b/1-js/05-data-types/10-date/3-weekday/solution.md index bfe3f4cac..e69de29bb 100644 --- a/1-js/05-data-types/10-date/3-weekday/solution.md +++ b/1-js/05-data-types/10-date/3-weekday/solution.md @@ -1,14 +0,0 @@ -```js run -function getLocalDay(date) { - - let day = date.getDay(); - - if (day == 0) { // 0 becomes 7 - day = 7; - } - - return day; -} - -alert( getLocalDay(new Date(2012, 0, 3)) ); // 2 -``` diff --git a/1-js/05-data-types/10-date/4-get-date-ago/solution.md b/1-js/05-data-types/10-date/4-get-date-ago/solution.md index 7abc7ab9c..5c394c100 100644 --- a/1-js/05-data-types/10-date/4-get-date-ago/solution.md +++ b/1-js/05-data-types/10-date/4-get-date-ago/solution.md @@ -11,7 +11,7 @@ function getDateAgo(date, days) { To implement it let's clone the date, like this: -```js run +```js run demo function getDateAgo(date, days) { let dateCopy = new Date(date); diff --git a/1-js/05-data-types/10-date/5-last-day-of-month/solution.md b/1-js/05-data-types/10-date/5-last-day-of-month/solution.md index 65f61c5ba..4f642536e 100644 --- a/1-js/05-data-types/10-date/5-last-day-of-month/solution.md +++ b/1-js/05-data-types/10-date/5-last-day-of-month/solution.md @@ -1,5 +1,5 @@ Let's create a date using the next month, but pass zero as the day: -```js run +```js run demo function getLastDayOfMonth(year, month) { let date = new Date(year, month + 1, 0); return date.getDate(); diff --git a/1-js/05-data-types/10-date/8-format-date-relative/solution.md b/1-js/05-data-types/10-date/8-format-date-relative/solution.md index 24fec997d..2507c840c 100644 --- a/1-js/05-data-types/10-date/8-format-date-relative/solution.md +++ b/1-js/05-data-types/10-date/8-format-date-relative/solution.md @@ -1,6 +1,6 @@ To get the time from `date` till now -- let's substract the dates. -```js run +```js run demo function formatDate(date) { let diff = new Date() - date; // the difference in milliseconds @@ -57,12 +57,12 @@ function formatDate(date) { let diffSec = Math.round(diffMs / 1000); let diffMin = diffSec / 60; let diffHour = diffMin / 60; - + // formatting year = year.toString().slice(-2); month = month < 10 ? '0' + month : month; dayOfMonth = dayOfMonth < 10 ? '0' + dayOfMonth : dayOfMonth; - + if (diffSec < 1) { return 'right now'; } else if (diffMin < 1) { diff --git a/1-js/05-data-types/11-json/article.md b/1-js/05-data-types/11-json/article.md index 9d5d6f0e6..0f526c59f 100644 --- a/1-js/05-data-types/11-json/article.md +++ b/1-js/05-data-types/11-json/article.md @@ -361,7 +361,7 @@ alert( JSON.stringify(meetup) ); Here we can see that `date` `(1)` became a string. That's because all dates have a built-in `toJSON` method which returns such kind of string. -Now let's add a custom `toJSON` for our object `room`: +Now let's add a custom `toJSON` for our object `room` `(2)`: ```js run let room = { diff --git a/1-js/05-data-types/11-json/json-meetup.png b/1-js/05-data-types/11-json/json-meetup.png index 0a26e0a67..56595ce96 100644 Binary files a/1-js/05-data-types/11-json/json-meetup.png and b/1-js/05-data-types/11-json/json-meetup.png differ diff --git a/1-js/05-data-types/11-json/json-meetup@2x.png b/1-js/05-data-types/11-json/json-meetup@2x.png index b5f6a4012..7a1f4436d 100644 Binary files a/1-js/05-data-types/11-json/json-meetup@2x.png and b/1-js/05-data-types/11-json/json-meetup@2x.png differ diff --git a/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/fibonacci-recursion-tree.png b/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/fibonacci-recursion-tree.png index c45418ff4..ce72de3e0 100644 Binary files a/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/fibonacci-recursion-tree.png and b/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/fibonacci-recursion-tree.png differ diff --git a/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/fibonacci-recursion-tree@2x.png b/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/fibonacci-recursion-tree@2x.png index 6fc39ae13..39df3d86f 100644 Binary files a/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/fibonacci-recursion-tree@2x.png and b/1-js/06-advanced-functions/01-recursion/03-fibonacci-numbers/fibonacci-recursion-tree@2x.png differ diff --git a/1-js/06-advanced-functions/01-recursion/linked-list-0.png b/1-js/06-advanced-functions/01-recursion/linked-list-0.png index 000a80da8..d2ebb4adc 100644 Binary files a/1-js/06-advanced-functions/01-recursion/linked-list-0.png and b/1-js/06-advanced-functions/01-recursion/linked-list-0.png differ diff --git a/1-js/06-advanced-functions/01-recursion/linked-list-0@2x.png b/1-js/06-advanced-functions/01-recursion/linked-list-0@2x.png index 5a2368694..2c02fdc20 100644 Binary files a/1-js/06-advanced-functions/01-recursion/linked-list-0@2x.png and b/1-js/06-advanced-functions/01-recursion/linked-list-0@2x.png differ diff --git a/1-js/06-advanced-functions/01-recursion/linked-list-remove-1.png b/1-js/06-advanced-functions/01-recursion/linked-list-remove-1.png index 477989ad8..c5123f2ec 100644 Binary files a/1-js/06-advanced-functions/01-recursion/linked-list-remove-1.png and b/1-js/06-advanced-functions/01-recursion/linked-list-remove-1.png differ diff --git a/1-js/06-advanced-functions/01-recursion/linked-list-remove-1@2x.png b/1-js/06-advanced-functions/01-recursion/linked-list-remove-1@2x.png index 41de7661c..24c990dbf 100644 Binary files a/1-js/06-advanced-functions/01-recursion/linked-list-remove-1@2x.png and b/1-js/06-advanced-functions/01-recursion/linked-list-remove-1@2x.png differ diff --git a/1-js/06-advanced-functions/01-recursion/linked-list-split.png b/1-js/06-advanced-functions/01-recursion/linked-list-split.png index ac2203490..f8e536414 100644 Binary files a/1-js/06-advanced-functions/01-recursion/linked-list-split.png and b/1-js/06-advanced-functions/01-recursion/linked-list-split.png differ diff --git a/1-js/06-advanced-functions/01-recursion/linked-list-split@2x.png b/1-js/06-advanced-functions/01-recursion/linked-list-split@2x.png index 201c66f15..b8e750bbc 100644 Binary files a/1-js/06-advanced-functions/01-recursion/linked-list-split@2x.png and b/1-js/06-advanced-functions/01-recursion/linked-list-split@2x.png differ diff --git a/1-js/06-advanced-functions/01-recursion/linked-list.png b/1-js/06-advanced-functions/01-recursion/linked-list.png index 64b6fb2b7..bffa6960c 100644 Binary files a/1-js/06-advanced-functions/01-recursion/linked-list.png and b/1-js/06-advanced-functions/01-recursion/linked-list.png differ diff --git a/1-js/06-advanced-functions/01-recursion/linked-list@2x.png b/1-js/06-advanced-functions/01-recursion/linked-list@2x.png index c28fa8259..a4ff44eeb 100644 Binary files a/1-js/06-advanced-functions/01-recursion/linked-list@2x.png and b/1-js/06-advanced-functions/01-recursion/linked-list@2x.png differ diff --git a/1-js/06-advanced-functions/01-recursion/recursion-pow.png b/1-js/06-advanced-functions/01-recursion/recursion-pow.png index 30577f89c..e2142a08e 100644 Binary files a/1-js/06-advanced-functions/01-recursion/recursion-pow.png and b/1-js/06-advanced-functions/01-recursion/recursion-pow.png differ diff --git a/1-js/06-advanced-functions/01-recursion/recursion-pow@2x.png b/1-js/06-advanced-functions/01-recursion/recursion-pow@2x.png index c19973420..36032173f 100644 Binary files a/1-js/06-advanced-functions/01-recursion/recursion-pow@2x.png and b/1-js/06-advanced-functions/01-recursion/recursion-pow@2x.png differ diff --git a/1-js/06-advanced-functions/01-recursion/recursive-salaries.png b/1-js/06-advanced-functions/01-recursion/recursive-salaries.png index 2b9015409..3de7e3093 100644 Binary files a/1-js/06-advanced-functions/01-recursion/recursive-salaries.png and b/1-js/06-advanced-functions/01-recursion/recursive-salaries.png differ diff --git a/1-js/06-advanced-functions/01-recursion/recursive-salaries@2x.png b/1-js/06-advanced-functions/01-recursion/recursive-salaries@2x.png index 261ab144e..7d7b13fc1 100644 Binary files a/1-js/06-advanced-functions/01-recursion/recursive-salaries@2x.png and b/1-js/06-advanced-functions/01-recursion/recursive-salaries@2x.png differ diff --git a/1-js/06-advanced-functions/03-closure/4-closure-sum/solution.md b/1-js/06-advanced-functions/03-closure/4-closure-sum/solution.md index e8c8c465c..a6679cd20 100644 --- a/1-js/06-advanced-functions/03-closure/4-closure-sum/solution.md +++ b/1-js/06-advanced-functions/03-closure/4-closure-sum/solution.md @@ -1,4 +1,4 @@ -For the second brackets to work, the first ones must return a function. +For the second parentheses to work, the first ones must return a function. Like this: diff --git a/1-js/06-advanced-functions/03-closure/4-closure-sum/task.md b/1-js/06-advanced-functions/03-closure/4-closure-sum/task.md index c2f3eabeb..b45758562 100644 --- a/1-js/06-advanced-functions/03-closure/4-closure-sum/task.md +++ b/1-js/06-advanced-functions/03-closure/4-closure-sum/task.md @@ -6,7 +6,7 @@ importance: 4 Write function `sum` that works like this: `sum(a)(b) = a+b`. -Yes, exactly this way, via double brackets (not a mistype). +Yes, exactly this way, using double parentheses (not a mistype). For instance: diff --git a/1-js/06-advanced-functions/03-closure/6-filter-through-function/solution.md b/1-js/06-advanced-functions/03-closure/6-filter-through-function/solution.md index 5bbc33b02..46c5514a8 100644 --- a/1-js/06-advanced-functions/03-closure/6-filter-through-function/solution.md +++ b/1-js/06-advanced-functions/03-closure/6-filter-through-function/solution.md @@ -14,7 +14,7 @@ alert( arr.filter(inBetween(3, 6)) ); // 3,4,5,6 # Filter inArray -```js run +```js run demo function inArray(arr) { return function(x) { return arr.includes(x); diff --git a/1-js/06-advanced-functions/03-closure/8-make-army/lexenv-makearmy.png b/1-js/06-advanced-functions/03-closure/8-make-army/lexenv-makearmy.png index d51e8167f..de84d79bf 100644 Binary files a/1-js/06-advanced-functions/03-closure/8-make-army/lexenv-makearmy.png and b/1-js/06-advanced-functions/03-closure/8-make-army/lexenv-makearmy.png differ diff --git a/1-js/06-advanced-functions/03-closure/8-make-army/lexenv-makearmy@2x.png b/1-js/06-advanced-functions/03-closure/8-make-army/lexenv-makearmy@2x.png index e70edbd6d..c5ad4b0df 100644 Binary files a/1-js/06-advanced-functions/03-closure/8-make-army/lexenv-makearmy@2x.png and b/1-js/06-advanced-functions/03-closure/8-make-army/lexenv-makearmy@2x.png differ diff --git a/1-js/06-advanced-functions/03-closure/8-make-army/solution.md b/1-js/06-advanced-functions/03-closure/8-make-army/solution.md index 03c34b075..f5afd4262 100644 --- a/1-js/06-advanced-functions/03-closure/8-make-army/solution.md +++ b/1-js/06-advanced-functions/03-closure/8-make-army/solution.md @@ -55,9 +55,9 @@ function makeArmy() { As a result, all `shooter` functions get from the outer lexical envrironment the same, last value `i=10`. -The fix can be very simple: +We can fix it by moving the variable definition into the loop: -```js run +```js run demo function makeArmy() { let shooters = []; @@ -80,9 +80,9 @@ army[0](); // 0 army[5](); // 5 ``` -Now it works correctly, because every time the code block in `for (..) {...}` is executed, a new Lexical Environment is created for it, with the corresponding value of `i`. +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. A `shooter` gets the value exactly from the one where it was created. +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.png) @@ -90,7 +90,6 @@ Here we rewrote `while` into `for`. Another trick could be possible, let's see it for better understanding of the subject: - ```js run function makeArmy() { let shooters = []; diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md index e6c95de0a..ac0e44c63 100644 --- a/1-js/06-advanced-functions/03-closure/article.md +++ b/1-js/06-advanced-functions/03-closure/article.md @@ -70,7 +70,7 @@ The Lexical Environment object consists of two parts: 1. *Environment Record* -- an object that has all local variables as its properties (and some other information like the value of `this`). 2. A reference to the *outer lexical environment*, usually the one associated with the code lexically right outside of it (outside of the current curly brackets). -So, a "variable" is just a property of the special internal object, Environment Record. "To get or change a variable" means "to get or change a property of the Lexical Environment". +**So, a "variable" is just a property of the special internal object, Environment Record. "To get or change a variable" means "to get or change a property of that object".** For instance, in this simple code, there is only one Lexical Environment: @@ -100,7 +100,11 @@ To summarize: ### Function Declaration -Function Declarations are special. Unlike `let` variables, they are processed not when the execution reaches them, but when a Lexical Environment is created. For the global Lexical Environment, it means the moment when the script is started. +Till now, we only observed variables. Now enter Function Declarations. + +**Unlike `let` variables, they are fully initialized not when the execution reaches them, but earlier, when a Lexical Environment is created.** + +For top-level functions, it means the moment when the script is started. That is why we can call a function declaration before it is defined. @@ -111,10 +115,14 @@ The code below demonstrates that the Lexical Environment is non-empty from the b ### Inner and outer Lexical Environment -During the call, `say()` uses an outer variable, so let's look at the details of what's going on. +Now let's go on and explore what happens when a function accesses an outer variable. + +During the call, `say()` uses the outer variable `phrase`, let's look at the details of what's going on. First, when a function runs, a new function Lexical Environment is created automatically. That's a general rule for all functions. That Lexical Environment is used to store local variables and parameters of the call. +For instance, for `say("John")`, it looks like this (the execution is at the line, labelled with an arrow): + -Here's the picture of Lexical Environments when the execution is inside `say("John")`, at the line labelled with an arrow: - ![lexical environment](lexical-environment-simple.png) -During the function call we have two Lexical Environments: the inner one (for the function call) and the outer one (global): +So, during the function call we have two Lexical Environments: the inner one (for the function call) and the outer one (global): + +- The inner Lexical Environment corresponds to the current execution of `say`. -- The inner Lexical Environment corresponds to the current execution of `say`. It has a single variable: `name`, the function argument. We called `say("John")`, so the value of `name` is `"John"`. + It has a single variable: `name`, the function argument. We called `say("John")`, so the value of `name` is `"John"`. - The outer Lexical Environment is the global Lexical Environment. -The inner Lexical Environment has the `outer` reference to the outer one. + It has `phrase` and the function itself. -**When code wants to access a variable -- it is first searched for in the inner Lexical Environment, then in the outer one, then the more outer one and so on until the end of the chain.** +The inner Lexical Environment has a reference to the outer one. + +**When the code wants to access a variable -- the inner Lexical Environment is searched first, then the outer one, then the more outer one and so on until the end of the chain.** If a variable is not found anywhere, that's an error in strict mode. Without `use strict`, an assignment to an undefined variable creates a new global variable, for backwards compatibility. Let's see how the search proceeds in our example: - When the `alert` inside `say` wants to access `name`, it finds it immediately in the function Lexical Environment. -- When it wants to access `phrase`, then there is no `phrase` locally, so it follows the `outer` reference and finds it globally. +- When it wants to access `phrase`, then there is no `phrase` locally, so it follows the reference to the enclosing Lexical Environment and finds it there. ![lexical environment lookup](lexical-environment-simple-lookup.png) @@ -211,11 +221,11 @@ function sayHiBye(firstName, lastName) { } ``` -Here the *nested* function `getFullName()` is made for convenience. It can access the outer variables and so can return the full name. +Here the *nested* function `getFullName()` is made for convenience. It can access the outer variables and so can return the full name. Nested functions are quite common in Javascript. -What's more interesting, a nested function can be returned: either as a property of a new object (if the outer function creates an object with methods) or as a result by itself. It can then be used somewhere else. No matter where, it still has access to the same outer variables. +What's much more interesting, a nested function can be returned: either as a property of a new object (if the outer function creates an object with methods) or as a result by itself. It can then be used somewhere else. No matter where, it still has access to the same outer variables. -An example with the constructor function (see the chapter ): +For instance, here the nested function is assigned to the new object by the [constructor function](info:constructor-new): ```js run // constructor function returns a new object @@ -228,10 +238,10 @@ function User(name) { } let user = new User("John"); -user.sayHi(); // the method code has access to the outer "name" +user.sayHi(); // the method "sayHi" code has access to the outer "name" ``` -An example with returning a function: +And here we just create and return a "counting" function: ```js run function makeCounter() { @@ -249,7 +259,7 @@ alert( counter() ); // 1 alert( counter() ); // 2 ``` -Let's go on with the `makeCounter` example. It creates the "counter" function that returns the next number on each invocation. Despite being simple, slightly modified variants of that code have practical uses, for instance, as a [pseudorandom number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator), and more. So the example is not as artificial as it may appear. +Let's go on with the `makeCounter` example. It creates the "counter" function that returns the next number on each invocation. Despite being simple, slightly modified variants of that code have practical uses, for instance, as a [pseudorandom number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator), and more. How does the counter work internally? @@ -265,7 +275,7 @@ In this example `count` is found on step `2`. When an outer variable is modifie Here are two questions to consider: -1. Can we somehow reset the `counter` from the code that doesn't belong to `makeCounter`? E.g. after `alert` calls in the example above. +1. Can we somehow reset the counter `count` from the code that doesn't belong to `makeCounter`? E.g. after `alert` calls in the example above. 2. If we call `makeCounter()` multiple times -- it returns many `counter` functions. Are they independent or do they share the same `count`? Try to answer them before you continue reading. @@ -276,8 +286,8 @@ All done? Okay, let's go over the answers. -1. There is no way. The `counter` is a local function variable, we can't access it from the outside. -2. For every call to `makeCounter()` a new function Lexical Environment is created, with its own `counter`. So the resulting `counter` functions are independent. +1. There is no way: `count` is a local function variable, we can't access it from the outside. +2. For every call to `makeCounter()` a new function Lexical Environment is created, with its own `count`. So the resulting `counter` functions are independent. Here's the demo: @@ -303,9 +313,11 @@ Hopefully, the situation with outer variables is quite clear for you now. But in ## Environments in detail -Now that you understand how closures work generally, we can descend to the very nuts and bolts. +Now that you understand how closures work generally, that's already very good. + +Here's what's going on in the `makeCounter` example step-by-step, follow it to make sure that you know things in the very detail. -Here's what's going on in the `makeCounter` example step-by-step, follow it to make sure that you understand everything. Please note the additional `[[Environment]]` property that we didn't cover yet. +Please note the additional `[[Environment]]` property is covered here. We didn't mention it before for simplicity. 1. When the script has just started, there is only global Lexical Environment: @@ -313,7 +325,7 @@ Here's what's going on in the `makeCounter` example step-by-step, follow it to m At that starting moment there is only `makeCounter` function, because it's a Function Declaration. It did not run yet. - All functions "on birth" receive a hidden property `[[Environment]]` with a reference to the Lexical Environment of their creation. We didn't talk about it yet, but that's how the function knows where it was made. + **All functions "on birth" receive a hidden property `[[Environment]]` with a reference to the Lexical Environment of their creation.** We didn't talk about it yet, but that's how the function knows where it was made. Here, `makeCounter` is created in the global Lexical Environment, so `[[Environment]]` keeps a reference to it. @@ -389,13 +401,13 @@ When on an interview, a frontend developer gets a question about "what's a closu ## Code blocks and loops, IIFE -The examples above concentrated on functions. But Lexical Environments also exist for code blocks `{...}`. +The examples above concentrated on functions. But a Lexical Environment exists for any code block `{...}`. -They are created when a code block runs and contain block-local variables. Here are a couple of examples. +A Lexical Environment is created when a code block runs and contains block-local variables. Here are a couple of examples. -## If +### If -In the example below, when the execution goes into `if` block, the new "if-only" Lexical Environment is created for it: +In the example below, the `user` variable exists only in the `if` block: - ```js untrusted run no-strict refresh - var phrase = "Hello"; +For historical reasons, in-browser `window` object is a bit messed up. - function sayHi() { - alert(phrase); - } +1. It provides the "browser window" functionality, besides playing the role of a global object. - // can read from window - alert( window.phrase ); // Hello (global var) - alert( window.sayHi ); // function (global function declaration) + We can use `window` to access properties and methods, specific to the browser window: - // can write to window (creates a new global variable) - window.test = 5; + ```js run + alert(window.innerHeight); // shows the browser window height - alert(test); // 5 + window.open('http://google.com'); // opens a new browser window ``` -...But the global object does not have variables declared with `let/const`! +2. Top-level `var` variables and function declarations automatically become properties of `window`. -```js untrusted run no-strict refresh -*!*let*/!* user = "John"; -alert(user); // John + For instance: + ```js untrusted run no-strict refresh + var x = 5; -alert(window.user); // undefined, don't have let -alert("user" in window); // false -``` + alert(window.x); // 5 (var x becomes a property of window) -```smart header="The global object is not a global Environment Record" -In versions of ECMAScript prior to ES-2015, there were no `let/const` variables, only `var`. And global object was used as a global Environment Record (wordings were a bit different, but that's the gist). + window.x = 0; -But starting from ES-2015, these entities are split apart. There's a global Lexical Environment with its Environment Record. And there's a global object that provides *some* of the global variables. + alert(x); // 0, variable modified + ``` -As a practical difference, global `let/const` variables are definitively properties of the global Environment Record, but they do not exist in the global object. + Please note, that doesn't happen with more modern `let/const` declarations: -Naturally, that's because the idea of a global object as a way to access "all global things" comes from ancient times. Nowadays is not considered to be a good thing. Modern language features like `let/const` do not make friends with it, but old ones are still compatible. -``` + ```js untrusted run no-strict refresh + let x = 5; -## Uses of "window" + alert(window.x); // undefined ("let" doesn't create a window property) + ``` -In server-side environments like Node.JS, the `global` object is used exceptionally rarely. Probably it would be fair to say "never". +3. Also, all scripts share the same global scope, so variables declared in one ` -Usually, it's not a good idea to use it, but here are some examples you can meet. + + ``` -1. To access exactly the global variable if the function has the local one with the same name. +4. And, a minor thing, but still: the value of `this` in the global scope is `window`. ```js untrusted run no-strict refresh - var user = "Global"; - - function sayHi() { - var user = "Local"; - - *!* - alert(window.user); // Global - */!* - } - - sayHi(); + alert(this); // window ``` - Such use is a workaround. Would be better to name variables differently, that won't require use to write the code it this way. And please note `"var"` before `user`. The trick doesn't work with `let` variables. +Why was it made like this? At the time of the language creation, the idea to merge multiple aspects into a single `window` object was to "make things simple". But since then many things changed. Tiny scripts became big applications that require proper architecture. -2. To check if a certain global variable or a builtin exists. +Is it good that different scripts (possibly from different sources) see variables of each other? - For instance, we want to check whether a global function `XMLHttpRequest` exists. +No, it's not, because it may lead to naming conflicts: the same variable name can be used in two scripts for different purposes, so they will conflict with each other. - We can't write `if (XMLHttpRequest)`, because if there's no `XMLHttpRequest`, there will be an error (variable not defined). +As of now, the multi-purpose `window` is considered a design mistake in the language. - But we can read it from `window.XMLHttpRequest`: +Luckily, there's a "road out of hell", called "Javascript modules". - ```js run - if (window.XMLHttpRequest) { - alert('XMLHttpRequest exists!') - } - ``` +If we set `type="module"` attribute on a ` ``` - This doesn't use `window`, but is (theoretically) less reliable, because `typeof` may use a local XMLHttpRequest, and we want the global one. +- Two modules that do not see variables of each other: + ```html run + -3. To take the variable from the right window. That's probably the most valid use case. + + ``` - A browser may open multiple windows and tabs. A window may also embed another one in ` - - ``` - Here, first two alerts use the current window, and the latter two take variables from `iframe` window. Can be any variables if `iframe` originates from the same protocol/host/port. +**Using ` + + diff --git a/6-async/04-promise-api/one.js b/1-js/11-async/04-promise-error-handling/one.js similarity index 100% rename from 6-async/04-promise-api/one.js rename to 1-js/11-async/04-promise-error-handling/one.js diff --git a/1-js/11-async/04-promise-error-handling/promise-handler-variants-2.png b/1-js/11-async/04-promise-error-handling/promise-handler-variants-2.png new file mode 100644 index 000000000..ada697605 Binary files /dev/null and b/1-js/11-async/04-promise-error-handling/promise-handler-variants-2.png differ diff --git a/1-js/11-async/04-promise-error-handling/promise-handler-variants-2@2x.png b/1-js/11-async/04-promise-error-handling/promise-handler-variants-2@2x.png new file mode 100644 index 000000000..7dd1d9efe Binary files /dev/null and b/1-js/11-async/04-promise-error-handling/promise-handler-variants-2@2x.png differ diff --git a/1-js/11-async/04-promise-error-handling/promise-handler-variants.png b/1-js/11-async/04-promise-error-handling/promise-handler-variants.png new file mode 100644 index 000000000..035eea197 Binary files /dev/null and b/1-js/11-async/04-promise-error-handling/promise-handler-variants.png differ diff --git a/1-js/11-async/04-promise-error-handling/promise-handler-variants@2x.png b/1-js/11-async/04-promise-error-handling/promise-handler-variants@2x.png new file mode 100644 index 000000000..98d0fa46b Binary files /dev/null and b/1-js/11-async/04-promise-error-handling/promise-handler-variants@2x.png differ diff --git a/1-js/11-async/04-promise-error-handling/promise-then-chain.png b/1-js/11-async/04-promise-error-handling/promise-then-chain.png new file mode 100644 index 000000000..52939e5fd Binary files /dev/null and b/1-js/11-async/04-promise-error-handling/promise-then-chain.png differ diff --git a/1-js/11-async/04-promise-error-handling/promise-then-chain@2x.png b/1-js/11-async/04-promise-error-handling/promise-then-chain@2x.png new file mode 100644 index 000000000..731f8c93c Binary files /dev/null and b/1-js/11-async/04-promise-error-handling/promise-then-chain@2x.png differ diff --git a/1-js/11-async/04-promise-error-handling/promise-then-many.png b/1-js/11-async/04-promise-error-handling/promise-then-many.png new file mode 100644 index 000000000..c37f6fe01 Binary files /dev/null and b/1-js/11-async/04-promise-error-handling/promise-then-many.png differ diff --git a/1-js/11-async/04-promise-error-handling/promise-then-many@2x.png b/1-js/11-async/04-promise-error-handling/promise-then-many@2x.png new file mode 100644 index 000000000..6fc13c2c6 Binary files /dev/null and b/1-js/11-async/04-promise-error-handling/promise-then-many@2x.png differ diff --git a/1-js/11-async/04-promise-error-handling/three.js b/1-js/11-async/04-promise-error-handling/three.js new file mode 100644 index 000000000..8536e85a1 --- /dev/null +++ b/1-js/11-async/04-promise-error-handling/three.js @@ -0,0 +1,3 @@ +function three() { + alert(3); +} diff --git a/6-async/04-promise-api/two.js b/1-js/11-async/04-promise-error-handling/two.js similarity index 100% rename from 6-async/04-promise-api/two.js rename to 1-js/11-async/04-promise-error-handling/two.js diff --git a/6-async/04-promise-api/iliakan.json b/1-js/11-async/04-promise-error-handling/user.json similarity index 100% rename from 6-async/04-promise-api/iliakan.json rename to 1-js/11-async/04-promise-error-handling/user.json diff --git a/6-async/04-promise-api/01-promise-errors-as-results/solution.md b/1-js/11-async/05-promise-api/01-promise-errors-as-results/solution.md similarity index 100% rename from 6-async/04-promise-api/01-promise-errors-as-results/solution.md rename to 1-js/11-async/05-promise-api/01-promise-errors-as-results/solution.md diff --git a/6-async/04-promise-api/01-promise-errors-as-results/solution.view/index.html b/1-js/11-async/05-promise-api/01-promise-errors-as-results/solution.view/index.html similarity index 100% rename from 6-async/04-promise-api/01-promise-errors-as-results/solution.view/index.html rename to 1-js/11-async/05-promise-api/01-promise-errors-as-results/solution.view/index.html diff --git a/6-async/04-promise-api/01-promise-errors-as-results/source.view/index.html b/1-js/11-async/05-promise-api/01-promise-errors-as-results/source.view/index.html similarity index 100% rename from 6-async/04-promise-api/01-promise-errors-as-results/source.view/index.html rename to 1-js/11-async/05-promise-api/01-promise-errors-as-results/source.view/index.html diff --git a/6-async/04-promise-api/01-promise-errors-as-results/task.md b/1-js/11-async/05-promise-api/01-promise-errors-as-results/task.md similarity index 94% rename from 6-async/04-promise-api/01-promise-errors-as-results/task.md rename to 1-js/11-async/05-promise-api/01-promise-errors-as-results/task.md index d6904f1bd..e4e77aeb0 100644 --- a/6-async/04-promise-api/01-promise-errors-as-results/task.md +++ b/1-js/11-async/05-promise-api/01-promise-errors-as-results/task.md @@ -20,7 +20,7 @@ Promise.all(urls.map(url => fetch(url))) }); ``` -The problem is that if any of requests fails, then `Promise.all` rejects with the error, and we loose results of all the other requests. +The problem is that if any of requests fails, then `Promise.all` rejects with the error, and we lose results of all the other requests. That's not good. diff --git a/6-async/04-promise-api/02-promise-errors-as-results-2/solution.md b/1-js/11-async/05-promise-api/02-promise-errors-as-results-2/solution.md similarity index 100% rename from 6-async/04-promise-api/02-promise-errors-as-results-2/solution.md rename to 1-js/11-async/05-promise-api/02-promise-errors-as-results-2/solution.md diff --git a/6-async/04-promise-api/02-promise-errors-as-results-2/solution.view/index.html b/1-js/11-async/05-promise-api/02-promise-errors-as-results-2/solution.view/index.html similarity index 100% rename from 6-async/04-promise-api/02-promise-errors-as-results-2/solution.view/index.html rename to 1-js/11-async/05-promise-api/02-promise-errors-as-results-2/solution.view/index.html diff --git a/6-async/04-promise-api/02-promise-errors-as-results-2/source.view/index.html b/1-js/11-async/05-promise-api/02-promise-errors-as-results-2/source.view/index.html similarity index 100% rename from 6-async/04-promise-api/02-promise-errors-as-results-2/source.view/index.html rename to 1-js/11-async/05-promise-api/02-promise-errors-as-results-2/source.view/index.html diff --git a/6-async/04-promise-api/02-promise-errors-as-results-2/task.md b/1-js/11-async/05-promise-api/02-promise-errors-as-results-2/task.md similarity index 88% rename from 6-async/04-promise-api/02-promise-errors-as-results-2/task.md rename to 1-js/11-async/05-promise-api/02-promise-errors-as-results-2/task.md index ec28728b0..50734a874 100644 --- a/6-async/04-promise-api/02-promise-errors-as-results-2/task.md +++ b/1-js/11-async/05-promise-api/02-promise-errors-as-results-2/task.md @@ -25,7 +25,7 @@ Promise.all(urls.map(url => fetch(url))) }); ``` -The problem is that if any of requests fails, then `Promise.all` rejects with the error, and we loose results of all the other requests. So the code above is not fault-tolerant, just like the one in the previous task. +The problem is that if any of requests fails, then `Promise.all` rejects with the error, and we lose results of all the other requests. So the code above is not fault-tolerant, just like the one in the previous task. Modify the code so that the array in the line `(*)` would include parsed JSON for successful requests and error for errored ones. diff --git a/6-async/04-promise-api/article.md b/1-js/11-async/05-promise-api/article.md similarity index 100% rename from 6-async/04-promise-api/article.md rename to 1-js/11-async/05-promise-api/article.md diff --git a/6-async/04-promise-api/head.html b/1-js/11-async/05-promise-api/head.html similarity index 100% rename from 6-async/04-promise-api/head.html rename to 1-js/11-async/05-promise-api/head.html diff --git a/1-js/11-async/05-promise-api/iliakan.json b/1-js/11-async/05-promise-api/iliakan.json new file mode 100644 index 000000000..32f89971a --- /dev/null +++ b/1-js/11-async/05-promise-api/iliakan.json @@ -0,0 +1,4 @@ +{ + "name": "iliakan", + "isAdmin": true +} diff --git a/1-js/11-async/05-promise-api/one.js b/1-js/11-async/05-promise-api/one.js new file mode 100644 index 000000000..948a60e07 --- /dev/null +++ b/1-js/11-async/05-promise-api/one.js @@ -0,0 +1,3 @@ +function one() { + alert(1); +} diff --git a/1-js/11-async/05-promise-api/two.js b/1-js/11-async/05-promise-api/two.js new file mode 100644 index 000000000..b04795b86 --- /dev/null +++ b/1-js/11-async/05-promise-api/two.js @@ -0,0 +1,3 @@ +function two() { + alert(2); +} diff --git a/6-async/05-async-await/01-rewrite-async-2/solution.md b/1-js/11-async/06-async-await/01-rewrite-async-2/solution.md similarity index 100% rename from 6-async/05-async-await/01-rewrite-async-2/solution.md rename to 1-js/11-async/06-async-await/01-rewrite-async-2/solution.md diff --git a/6-async/05-async-await/01-rewrite-async-2/task.md b/1-js/11-async/06-async-await/01-rewrite-async-2/task.md similarity index 100% rename from 6-async/05-async-await/01-rewrite-async-2/task.md rename to 1-js/11-async/06-async-await/01-rewrite-async-2/task.md diff --git a/6-async/05-async-await/01-rewrite-async/solution.md b/1-js/11-async/06-async-await/01-rewrite-async/solution.md similarity index 100% rename from 6-async/05-async-await/01-rewrite-async/solution.md rename to 1-js/11-async/06-async-await/01-rewrite-async/solution.md diff --git a/6-async/05-async-await/01-rewrite-async/task.md b/1-js/11-async/06-async-await/01-rewrite-async/task.md similarity index 100% rename from 6-async/05-async-await/01-rewrite-async/task.md rename to 1-js/11-async/06-async-await/01-rewrite-async/task.md diff --git a/6-async/05-async-await/article.md b/1-js/11-async/06-async-await/article.md similarity index 97% rename from 6-async/05-async-await/article.md rename to 1-js/11-async/06-async-await/article.md index 5989fd731..63f50cc0c 100644 --- a/6-async/05-async-await/article.md +++ b/1-js/11-async/06-async-await/article.md @@ -12,7 +12,7 @@ async function f() { } ``` -The word "async" before a function means one simple thing: a function always returns a promise. If the code has `return ` in it, then JavaScript automatically wraps it into a resolved promise with that value. +The word "async" before a function means one simple thing: a function always returns a promise. Even If a function actually returns a non-promise value, prepending the function definition with the "async" keyword directs Javascript to automatically wrap that value in a resolved promise. For instance, the code above returns a resolved promise with the result of `1`, let's test it: diff --git a/6-async/05-async-await/head.html b/1-js/11-async/06-async-await/head.html similarity index 100% rename from 6-async/05-async-await/head.html rename to 1-js/11-async/06-async-await/head.html diff --git a/1-js/11-async/07-async-iteration-generators/article.md b/1-js/11-async/07-async-iteration-generators/article.md new file mode 100644 index 000000000..743f57064 --- /dev/null +++ b/1-js/11-async/07-async-iteration-generators/article.md @@ -0,0 +1,361 @@ + +# Async iteration and generators + +Asynchronous iterators allow to iterate over data that comes asynchronously, on-demand. + +For instance, when we download something chunk-by-chunk, or just expect events to come asynchronously and would like to iterate over them -- async iterators and generators may come in handy. Let's see a simple example first, to grasp the syntax, and then review a real-life use case. + +## Async iterators + +Asynchronous iterators are totally similar to regular iterators, with a few syntactic differences. + +"Regular" iterable object from the chapter look like this: + +```js run +let range = { + from: 1, + to: 5, + + // for..of calls this method once in the very beginning +*!* + [Symbol.iterator]() { +*/!* + // ...it returns the iterator object: + // onward, for..of works only with that object, asking it for next values + return { + current: this.from, + last: this.to, + + // next() is called on each iteration by the for..of loop +*!* + next() { // (2) + // it should return the value as an object {done:.., value :...} +*/!* + if (this.current <= this.last) { + return { done: false, value: this.current++ }; + } else { + return { done: true }; + } + } + }; + } +}; + +for(let value in range) { + alert(value); // 1 then 2, then 3, then 4, then 5 +} +``` + +If necessary, please refer to the [chapter about iterables](info:iterable) for details about regular iterators. + +To make the object iterable asynchronously: +1. We need to use `Symbol.asyncIterator` instead of `Symbol.iterator`. +2. `next()` should return a promise. +3. To iterate over such an object, we should use `for await (let item of iterable)` loop. + +Let's make an iterable `range` object, like the one before, but now it will return values asynchronously, one per second: + +```js run +let range = { + from: 1, + to: 5, + + // for await..of calls this method once in the very beginning +*!* + [Symbol.asyncIterator]() { // (1) +*/!* + // ...it returns the iterator object: + // onward, for await..of works only with that object, asking it for next values + return { + current: this.from, + last: this.to, + + // next() is called on each iteration by the for..of loop +*!* + async next() { // (2) + // it should return the value as an object {done:.., value :...} + // (automatically wrapped into a promise by async) +*/!* + + // can use await inside, do async stuff: + await new Promise(resolve => setTimeout(resolve, 1000)); // (3) + + if (this.current <= this.last) { + return { done: false, value: this.current++ }; + } else { + return { done: true }; + } + } + }; + } +}; + +(async () => { + +*!* + for await (let value of range) { // (4) + alert(value); // 1,2,3,4,5 + } +*/!* + +})() +``` + +As we can see, the components are similar to regular iterators: + +1. To make an object asynchronously iterable, it must have a method `Symbol.asyncIterator` `(1)`. +2. It must return the object with `next()` method returning a promise `(2)`. +3. The `next()` method doesn't have to be `async`, it may be a regular method returning a promise, but `async` allows to use `await` inside. Here we just delay for a second `(3)`. +4. To iterate, we use `for await(let value of range)` `(4)`, namely add "await" after "for". It calls `range[Symbol.asyncIterator]()` once, and then its `next()` for values. + +Here's a small cheatsheet: + +| | Iterators | Async iterators | +|-------|-----------|-----------------| +| Object method to provide iteraterable | `Symbol.iterator` | `Symbol.asyncIterator` | +| `next()` return value is | any value | `Promise` | +| to loop, use | `for..of` | `for await..of` | + + +````warn header="The spread operator doesn't work asynchronously" +Features that require regular, synchronous iterators, don't work with asynchronous ones. + +For instance, a spread operator won't work: +```js +alert( [...range] ); // Error, no Symbol.iterator +``` + +That's natural, as it expects to find `Symbol.iterator`, same as `for..of` without `await`. +```` + +## Async generators + +Javascript also provides generators, that are also iterable. + +Let's recall a sequence generator from the chapter [](info:generators). It generates a sequence of values from `start` to `end` (could be anything else): + +```js run +function* generateSequence(start, end) { + for (let i = start; i <= end; i++) { + yield i; + } +} + +for(let value of generateSequence(1, 5)) { + alert(value); // 1, then 2, then 3, then 4, then 5 +} +``` + + +Normally, we can't use `await` in generators. All values must come synchronously: there's no place for delay in `for..of`. + +But what if we need to use `await` in the generator body? To perform network requests, for instance. + +No problem, just prepend it with `async`, like this: + +```js run +*!*async*/!* function* generateSequence(start, end) { + + for (let i = start; i <= end; i++) { + +*!* + // yay, can use await! + await new Promise(resolve => setTimeout(resolve, 1000)); +*/!* + + yield i; + } + +} + +(async () => { + + let generator = generateSequence(1, 5); + for *!*await*/!* (let value of generator) { + alert(value); // 1, then 2, then 3, then 4, then 5 + } + +})(); +``` + +Now we have an the async generator, iteratable with `for await...of`. + +It's indeed very simple. We add the `async` keyword, and the generator now can use `await` inside of it, rely on promises and other async functions. + +Technically, another the difference of an async generator is that its `generator.next()` method is now asynchronous also, it returns promises. + +Instead of `result = generator.next()` for a regular, non-async generator, values can be obtained like this: + +```js +result = await generator.next(); // result = {value: ..., done: true/false} +``` + +## Iterables via async generators + +When we'd like to make an object iterable, we should add `Symbol.iterator` to it. + +```js +let range = { + from: 1, + to: 5, +*!* + [Symbol.iterator]() { ...return object with next to make range iterable... } +*/!* +} +``` + +A common practice for `Symbol.iterator` is to return a generator, rather than a plain object with `next` as in the example before. + +Let's recall an example from the chapter [](info:generators): + +```js run +let range = { + from: 1, + to: 5, + + *[Symbol.iterator]() { // a shorthand for [Symbol.iterator]: function*() + for(let value = this.from; value <= this.to; value++) { + yield value; + } + } +}; + +for(let value of range) { + alert(value); // 1, then 2, then 3, then 4, then 5 +} +``` + +Here a custom object `range` is iterable, and the generator `*[Symbol.iterator]` implements the logic for listing values. + +If we'd like to add async actions into the generator, then we should replace `Symbol.iterator` with async `Symbol.asyncIterator`: + +```js run +let range = { + from: 1, + to: 5, + +*!* + async *[Symbol.asyncIterator]() { // same as [Symbol.asyncIterator]: async function*() +*/!* + for(let value = this.from; value <= this.to; value++) { + + // make a pause between values, wait for something + await new Promise(resolve => setTimeout(resolve, 1000)); + + yield value; + } + } +}; + +(async () => { + + for *!*await*/!* (let value of range) { + alert(value); // 1, then 2, then 3, then 4, then 5 + } + +})(); +``` + +Now values come with a delay of 1 second between them. + +## Real-life example + +So far we've seen simple examples, to gain basic understanding. Now let's review a real-life use case. + +There are many online APIs that deliver paginated data. For instance, when we need a list of users, then we can fetch it page-by-page: a request returns a pre-defined count (e.g. 100 users), and provides an URL to the next page. + +The pattern is very common, it's not about users, but just about anything. For instance, Github allows to retrieve commits in the same, paginated fasion: + +- We should make a request to URL in the form `https://api.github.com/repos//commits`. +- It responds with a JSON of 30 commits, and also provides a link to the next page in the `Link` header. +- Then we can use that link for the next request, to get more commits, and so on. + +What we'd like to have is an iterable source of commits, so that we could use it like this: + +```js +let repo = 'iliakan/javascript-tutorial-en'; // Github repository to get commits from + +for await (let commit of fetchCommits(repo)) { + // process commit +} +``` + +We'd like `fetchCommits` to get commits for us, making requests whenever needed. And let it care about all pagination stuff, for us it'll be a simple `for await..of`. + +With async generators that's pretty easy to implement: + +```js +async function* fetchCommits(repo) { + let url = `https://api.github.com/repos/${repo}/commits`; + + while (url) { + const response = await fetch(url, { // (1) + headers: {'User-Agent': 'Our script'}, // github requires user-agent header + }); + + const body = await response.json(); // (2) parses response as JSON (array of commits) + + // (3) the URL of the next page is in the headers, extract it + let nextPage = response.headers.get('Link').match(/<(.*?)>; rel="next"/); + nextPage = nextPage && nextPage[1]; + + url = nextPage; + + for(let commit of body) { // (4) yield commits one by one, until the page ends + yield commit; + } + } +} +``` + +1. We use the browser `fetch` method to download from a remote URL. It allows to supply authorization and other headers if needed, here Github requires `User-Agent`. +2. The fetch result is parsed as JSON, that's again a `fetch`-specific method. +3. We can get the next page URL from the `Link` header of the response. It has a special format, so we use a regexp for that. The next page URL may look like this: `https://api.github.com/repositories/93253246/commits?page=2`, it's generatd by Github itself. +4. Then we yield all commits received, and when they finish -- the next `while(url)` iteration will trigger, making one more request. + +An example of use (shows commit authors in console): + +```js run +(async () => { + + let count = 0; + + for await (const commit of fetchCommits('iliakan/javascript-tutorial-en')) { + + console.log(commit.author.login); + + if (++count == 100) { // let's stop at 100 commits + break; + } + } + +})(); +``` + +That's just what we wanted. The internal pagination mechanics is invisible from the outside. For us it's just an async generator that returns commits. + +## Summary + +Regular iterators and generators work fine with the data that doesn't take time to generate. + +When we expect the data to come asynchronously, with delays, their async counterparts can be used, and `for await..of` instead of `for..of`. + +Syntax differences between async and regular iterators: + +| | Iterators | Async iterators | +|-------|-----------|-----------------| +| Object method to provide iteraterable | `Symbol.iterator` | `Symbol.asyncIterator` | +| `next()` return value is | any value | `Promise` | + +Syntax differences between async and regular generators: + +| | Generators | Async generators | +|-------|-----------|-----------------| +| Declaration | `function*` | `async function*` | +| `generator.next()` returns | `{value:…, done: true/false}` | `Promise` that resolves to `{value:…, done: true/false}` | + +In web-development we often meet streams of data, when it flows chunk-by-chunk. For instance, downloading or uploading a big file. + +We could use async generators to process such data, but there's also another API called Streams, that may be more convenient, as it provides special interfaces to transform the data and to pass it from one stream to another (e.g. download from one place and immediately send elsewhere). But they are also more complex. + +Streams API not a part of Javascript language standard. Streams and async generators complement each other, both are great ways to handle async data flows. diff --git a/1-js/11-async/07-async-iteration-generators/head.html b/1-js/11-async/07-async-iteration-generators/head.html new file mode 100644 index 000000000..74d66a8b8 --- /dev/null +++ b/1-js/11-async/07-async-iteration-generators/head.html @@ -0,0 +1,24 @@ + diff --git a/6-async/index.md b/1-js/11-async/index.md similarity index 100% rename from 6-async/index.md rename to 1-js/11-async/index.md diff --git a/1-js/12-modules/01-modules-intro/article.md b/1-js/12-modules/01-modules-intro/article.md new file mode 100644 index 000000000..ad83d4254 --- /dev/null +++ b/1-js/12-modules/01-modules-intro/article.md @@ -0,0 +1,375 @@ + +# Modules, introduction + +As our application grows bigger, we want to split it into multiple files, so called 'modules'. +A module usually contains a class or a library of useful functions. + +For a long time, Javascript existed without a language-level module syntax. That wasn't a problem, because initially scripts were small and simple. So there was no need. + +But eventually scripts became more and more complex, so the community invented a variety of ways to organize code into modules. + +For instance: + +- [AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition) -- one of the most ancient module systems, initially implemented by the library [require.js](http://requirejs.org/). +- [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) -- the module system created for Node.JS server. +- [UMD](https://github.com/umdjs/umd) -- one more module system, suggested as a universal one, compatible with AMD and CommonJS. + +Now all these slowly become a part of history, but we still can find them in old scripts. The language-level module system appeared in the standard in 2015, gradually evolved since then, and is now supported by all major browsers and in Node.js. + +## What is a module? + +A module is just a file, a single script, as simple as that. + +Directives `export` and `import` allow to interchange functionality between modules: + +- `export` keyword labels variables and functions that should be accessible from outside the file. +- `import` allows to import functionality from other modules. + +For instance, if we have a file `sayHi.js` exporting a function: + +```js +// 📁 sayHi.js +export function sayHi(user) { + alert(`Hello, ${user}!`); +} +``` + +...Then another file may import and use it: + +```js +// 📁 main.js +import {sayHi} from './sayHi.js'; + +alert(sayHi); // function... +sayHi('John'); // Hello, John! +``` + +In this tutorial we concentrate on the language itself, but we use browser as the demo environment, so let's see how modules work in the browser. + +To use modules, we must set the attribute ` +``` + +Here we can see it in the browser, but the same is true for any module. + +### Module-level scope + +Each module has its own top-level scope. In other words, top-level variables and functions from a module are not seen in other scripts. + +In the example below, two scripts are imported, and `hello.js` tries to use `user` variable declared in `user.js`, and fails: + +[codetabs src="scopes" height="140" current="index.html"] + +Modules are expected to `export` what they want to be accessible from outside and `import` what they need. + +So we should import `user.js` directly into `hello.js` instead of `index.html`. + +That's the correct variant: + +[codetabs src="scopes-working" height="140" current="hello.js"] + +In the browser, independant top-level scope also exists for each ` + + +``` + +If we really need to make a "global" in-browser variable, we can explicitly assign it to `window` and access as `window.user`. But that's an exception requiring a good reason. + +### A module code is evaluated only the first time when imported + +If a same module is imported into multiple other places, it's code is executed only the first time, then exports are given to all importers. + +That has important consequences. Let's see that on examples. + +First, if executing a module code brings side-effects, like showing a message, then importing it multiple times will trigger it only once -- the first time: + +```js +// 📁 alert.js +alert("Module is evaluated!"); +``` + +```js +// Import the same module from different files + +// 📁 1.js +import `./alert.js`; // Module is evaluated! + +// 📁 2.js +import `./alert.js`; // (nothing) +``` + +In practice, top-level module code is mostly used for initialization. We create data structures, pre-fill them, and if we want something to be reusable -- export it. + +Now, a more advanced example. + +Let's say, a module exports an object: + +```js +// 📁 admin.js +export let admin = { + name: "John" +}; +``` + +If this module is imported from multiple files, the module is only evaluated the first time, `admin` object is created, and then passed to all further importers. + +All importers get exactly the one and only `admin` object: + +```js +// 📁 1.js +import {admin} from './admin.js'; +admin.name = "Pete"; + +// 📁 2.js +import {admin} from './admin.js'; +alert(admin.name); // Pete + +*!* +// Both 1.js and 2.js imported the same object +// Changes made in 1.js are visible in 2.js +*/!* +``` + +So, let's reiterate -- the module is executed only once. Exports are generated, and then they are shared between importers, so if something changes the `admin` object, other modules will see that . + +Such behavior is great for modules that require configuration. We can set required properties on the first import, and then in further imports it's ready. + +For instance, `admin.js` module may provide certain functionality, but expect the credentials to come into the `admin` object from outside: + +```js +// 📁 admin.js +export let admin = { }; + +export function sayHi() { + alert(`Ready to serve, ${admin.name}!`); +} +``` + +Now, in `init.js`, the first script of our app, we set `admin.name`. Then everyone will see it, including calls made from inside `admin.js` itself: + +```js +// 📁 init.js +import {admin} from './admin.js'; +admin.name = "Pete"; +``` + +```js +// 📁 other.js +import {admin, sayHi} from './admin.js'; + +alert(admin.name); // *!*Pete*/!* + +sayHi(); // Ready to serve, *!*Pete*/!*! +``` + +### import.meta + +The object `import.meta` contains the information about the current module. + +Its content depends on the environment. In the browser, it contains the url of the script, or a current webpage url if inside HTML: + +```html run height=0 + +``` + +### Top-level "this" is undefined + +That's kind of a minor feature, but for completeness we should mention it. + +In a module, top-level `this` is undefined, as opposed to a global object in non-module scripts: + +```html run height=0 + + + +``` + +## Browser-specific features + +There are also several browser-specific differences of scripts with `type="module"` compared to regular ones. + +You may want skip those for now if you're reading for the first time, or if you don't use Javascript in a browser. + +### Module scripts are deferred + +Module scripts are *always* deferred, same effect as `defer` attribute (described in the chapter [](info:onload-ondomcontentloaded)), for both external and inline scripts. + +In other words: +- external module scripts ` + + + + +``` + +Please note: the second script actually works before the first! So we'll see `undefined` first, and then `object`. + +That's because modules are deferred, so way wait for the document to be processed. The regular scripts runs immediately, so we saw its output first. + +When using modules, we should be aware that HTML-document can show up before the Javascript application is ready. Some functionality may not work yet. We should put transparent overlays or "loading indicators", or otherwise ensure that the visitor won't be confused because of it. + +### Async works on inline scripts + +Async attribute ` +``` + +### External scripts + +There are two notable differences of external module scripts: + +1. External scripts with same `src` run only once: + ```html + + + + ``` + +2. External scripts that are fetched from another domain require [CORS](mdn:Web/HTTP/CORS) headers. In other words, if a module script is fetched from another domain, the remote server must supply a header `Access-Control-Allow-Origin: *` (may use fetching domain instead of `*`) to indicate that the fetch is allowed. + ```html + + + + ``` + + That ensures better security by default. + +### No bare modules allowed + +In the browser, in scripts (not in HTML), `import` must get either a relative or absolute URL. So-called "bare" modules, without a path, are not allowed. + +For instance, this `import` is invalid: +```js +import {sayHi} from 'sayHi'; // Error, "bare" module +// must be './sayHi.js' or wherever the module is +``` + +Certain environments, like Node.js or bundle tools allow bare modules, as they have own ways for finding modules and hooks to fine-tune them. But browsers do not support bare modules yet. + +### Compatibility, "nomodule" + +Old browsers do not understand `type="module"`. Scripts of the unknown type are just ignored. For them, it's possible to provide a fallback using `nomodule` attribute: + +```html run + + + +``` + +If we use bundle tools, then as modules are bundled together, their `import/export` statements are replaced by special bundler calls, so the resulting build does not require `type="module"`, and we can put it into a regular script: + +```html + + +``` + +## Build tools + +In real-life, browser modules are rarely used in their "raw" form. Usually, we bundle them together with a special tool such as [Webpack](https://webpack.js.org/) and deploy to the production server. + +One of the benefits of using bundlers -- they give more control over how modules are resolved, allowing bare modules and much more, like CSS/HTML modules. + +Build tools do the following: + +1. Take a "main" module, the one intended to be put in ` diff --git a/1-js/12-modules/01-modules-intro/say.view/say.js b/1-js/12-modules/01-modules-intro/say.view/say.js new file mode 100644 index 000000000..198a3be6d --- /dev/null +++ b/1-js/12-modules/01-modules-intro/say.view/say.js @@ -0,0 +1,3 @@ +export function sayHi(user) { + return `Hello, ${user}!`; +} diff --git a/1-js/12-modules/01-modules-intro/scopes-working.view/hello.js b/1-js/12-modules/01-modules-intro/scopes-working.view/hello.js new file mode 100644 index 000000000..6c087ea81 --- /dev/null +++ b/1-js/12-modules/01-modules-intro/scopes-working.view/hello.js @@ -0,0 +1,3 @@ +import {user} from './user.js'; + +document.body.innerHTML = user; // John diff --git a/1-js/12-modules/01-modules-intro/scopes-working.view/index.html b/1-js/12-modules/01-modules-intro/scopes-working.view/index.html new file mode 100644 index 000000000..b78f75912 --- /dev/null +++ b/1-js/12-modules/01-modules-intro/scopes-working.view/index.html @@ -0,0 +1,2 @@ + + diff --git a/1-js/12-modules/01-modules-intro/scopes-working.view/user.js b/1-js/12-modules/01-modules-intro/scopes-working.view/user.js new file mode 100644 index 000000000..d289329c6 --- /dev/null +++ b/1-js/12-modules/01-modules-intro/scopes-working.view/user.js @@ -0,0 +1 @@ +export let user = "John"; diff --git a/1-js/12-modules/01-modules-intro/scopes.view/hello.js b/1-js/12-modules/01-modules-intro/scopes.view/hello.js new file mode 100644 index 000000000..714aafa1f --- /dev/null +++ b/1-js/12-modules/01-modules-intro/scopes.view/hello.js @@ -0,0 +1 @@ +alert(user); // no such variable (each module has independent variables) diff --git a/1-js/12-modules/01-modules-intro/scopes.view/index.html b/1-js/12-modules/01-modules-intro/scopes.view/index.html new file mode 100644 index 000000000..a87e96fdf --- /dev/null +++ b/1-js/12-modules/01-modules-intro/scopes.view/index.html @@ -0,0 +1,3 @@ + + + diff --git a/1-js/12-modules/01-modules-intro/scopes.view/user.js b/1-js/12-modules/01-modules-intro/scopes.view/user.js new file mode 100644 index 000000000..12ec850d9 --- /dev/null +++ b/1-js/12-modules/01-modules-intro/scopes.view/user.js @@ -0,0 +1 @@ +let user = "John"; diff --git a/1-js/12-modules/02-import-export/article.md b/1-js/12-modules/02-import-export/article.md new file mode 100644 index 000000000..dbeb15405 --- /dev/null +++ b/1-js/12-modules/02-import-export/article.md @@ -0,0 +1,438 @@ + +# Export and Import + +Export and import directives are very versatile. + +In the previous chapter we saw a simple use, now let's explore more examples. + +## Export before declarations + +We can label any declaration as exported by placing `export` before it, be it a variable, function or a class. + +For instance, here all exports are valid: + +```js +// export an array +*!*export*/!* let months = ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + +// export a constant +*!*export*/!* const MODULES_BECAME_STANDARD_YEAR = 2015; + +// export a class +*!*export*/!* class User { + constructor(name) { + this.name = name; + } +} +``` + +````smart header="No semicolons after export class/function" +Please note that `export` before a class or a function does not make it a [function expression](info:function-expressions-arrows). It's still a function declaration, albeit exported. + +Most Javascript style guides recommend semicolons after statements, but not after function and class declarations. + +That's why there should be no semicolons at the end of `export class` and `export function`. + +```js +export function sayHi(user) { + alert(`Hello, ${user}!`); +} *!* // no ; at the end */!* +``` + +```` + +## Export apart from declarations + +Also, we can put `export` separately. + +Here we first declare, and then export: + +```js +// 📁 say.js +function sayHi(user) { + alert(`Hello, ${user}!`); +} + +function sayBye(user) { + alert(`Bye, ${user}!`); +} + +*!* +export {sayHi, sayBye}; // a list of exported variables +*/!* +``` + +...Or, technically we could put `export` above functions as well. + +## Import * + +Usually, we put a list of what to import into `import {...}`, like this: + +```js +// 📁 main.js +*!* +import {sayHi, sayBye} from './say.js'; +*/!* + +sayHi('John'); // Hello, John! +sayBye('John'); // Bye, John! +``` + +But if the list is long, we can import everything as an object using `import * as `, for instance: + +```js +// 📁 main.js +*!* +import * as say from './say.js'; +*/!* + +say.sayHi('John'); +say.sayBye('John'); +``` + +At first sight, "import everything" seems such a cool thing, short to write, why should we ever explicitly list what we need to import? + +Well, there are few reasons. + +1. Modern build tools ([webpack](http://webpack.github.io) and others) bundle modules together and optimize them to speedup loading and remove unused stuff. + + Let's say, we added a 3rd-party library `lib.js` to our project with many functions: + ```js + // 📁 lib.js + export function sayHi() { ... } + export function sayBye() { ... } + export function becomeSilent() { ... } + ``` + + Now if we in fact need only one of them in our project: + ```js + // 📁 main.js + import {sayHi} from './lib.js'; + ``` + ...Then the optimizer will automatically detect it and totally remove the other functions from the bundled code, thus making the build smaller. That is called "tree-shaking". + +2. Explicitly listing what to import gives shorter names: `sayHi()` instead of `lib.sayHi()`. +3. Explicit imports give better overview of the code structure: what is used and where. It makes code support and refactoring easier. + +## Import "as" + +We can also use `as` to import under different names. + +For instance, let's import `sayHi` into the local variable `hi` for brevity, and same for `sayBye`: + +```js +// 📁 main.js +*!* +import {sayHi as hi, sayBye as bye} from './say.js'; +*/!* + +hi('John'); // Hello, John! +bye('John'); // Bye, John! +``` + +## Export "as" + +The similar syntax exists for `export`. + +Let's export functions as `hi` and `bye`: + +```js +// 📁 say.js +... +export {sayHi as hi, sayBye as bye}; +``` + +Now `hi` and `bye` are official names for outsiders: + +```js +// 📁 main.js +import * as say from './say.js'; + +say.hi('John'); // Hello, John! +say.bye('John'); // Bye, John! +``` + +## export default + +So far, we've seen how to import/export multiple things, optionally "as" other names. + +In practice, modules contain either: +- A library, pack of functions, like `lib.js`. +- Or an entity, like `class User` is descirbed in `user.js`, the whole module has only this class. + +Mostly, the second approach is preferred, so that every "thing" resides in its own module. + +Naturally, that requires a lot of files, as everything wants its own module, but that's not a problem at all. Actually, code navigation becomes easier, if files are well-named and structured into folders. + +Modules provide special `export default` syntax to make "one thing per module" way look better. + +It requires following `export` and `import` statements: + +1. Put `export default` before the "main export" of the module. +2. Call `import` without curly braces. + +For instance, here `user.js` exports `class User`: + +```js +// 📁 user.js +export *!*default*/!* class User { // just add "default" + constructor(name) { + this.name = name; + } +} +``` + +...And `main.js` imports it: + +```js +// 📁 main.js +import *!*User*/!* from './user.js'; // not {User}, just User + +new User('John'); +``` + +Imports without curly braces look nicer. A common mistake when starting to use modules is to forget curly braces at all. So, remember, `import` needs curly braces for named imports and doesn't need them for the default one. + +| Named export | Default export | +|--------------|----------------| +| `export class User {...}` | `export default class User {...}` | +| `import {User} from ...` | `import User from ...`| + +Naturally, there may be only one "default" export per file. + +We may have both default and named exports in a single module, but in practice people usually don't mix them. A module has either named exports or the default one. + +**Another thing to note is that named exports must (naturally) have a name, while `export default` may be anonymous.** + +For instance, these are all perfecly valid default exports: + +```js +export default class { // no class name + constructor() { ... } +} + +export default function(user) { // no function name + alert(`Hello, ${user}!`); +} + +// export a single value, without making a variable +export default ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; +``` + +That's fine, because `export default` is only one per file, so `import` always knows what to import. + Contrary to that, omitting a name for named imports would be an error: + +```js +export class { // Error! (non-default export needs a name) + constructor() {} +} +``` + +### "Default" alias + +The "default" word is a kind of "alias" for the default export, for scenarios when we need to reference it somehow. + +For example, if we already have a function declared, that's how to `export default` it: + +```js +function sayHi(user) { + alert(`Hello, ${user}!`); +} + +export {sayHi as default}; // same as if we added "export default" before the function +``` + +Or, let's say a module `user.js` exports one main "default" thing and a few named ones (rarely the case, but happens): + +```js +// 📁 user.js +export default class User { + constructor(name) { + this.name = name; + } +} + +export function sayHi(user) { + alert(`Hello, ${user}!`); +} +``` + +Here's how to import the default export along with a named one: + +```js +// 📁 main.js +import {*!*default as User*/!*, sayHi} from './user.js'; + +new User('John'); +``` + +Or, if we consider importing `*` as an object, then the `default` property is exactly the default export: + +```js +// 📁 main.js +import * as user from './user.js'; + +let User = user.default; +new User('John'); +``` + + +### Should I use default exports? + +One should be careful about using default exports, because they are somewhat more different to maintain. + +Named exports are explicit. They exactly name what they import, so we have that information from them, that's a good thing. + +Also, named exports enforce us to use exactly the right name to import: + +```js +import {User} from './user.js'; +``` + +For default exports, we need to create a name on our own: + +```js +import MyUser from './user.js'; // could be import Anything..., and it'll work +``` + +So, there's a little bit more freedom that can be abused, so that team members may use different names for the same thing. + +Usually, to avoid that and keep the code consistent, there's a rule that imported variables should correspond to file names, e.g: + +```js +import User from './user.js'; +import LoginForm from './loginForm.js'; +import func from '/path/to/func.js'; +... +``` + +Another solution would be to use named exports everywhere. Even if only a single thing is exported, it's still exported under a name, without `default`. + +That also makes re-export (see below) a little bit easier. + +## Re-export + +"Re-export" syntax `export ... from ...` allows to import things and immediately export them (possibly under another name), like this: + +```js +export {sayHi} from './say.js'; +export {default as User} from './user.js'; +``` + +What's the point, why that's needed? Let's see a practical use case. + +Imagine, we're writing a "package": a folder with a lot of modules, mostly needed internally, with some of the functionality exported outside (tools like NPM allow to publish and distribute packages, but here it doesn't matter). + +A directory structure could be like this: +``` +auth/ + index.js + user.js + helpers.js + tests/ + login.js + providers/ + github.js + facebook.js + ... +``` + +We'd like to expose the package functionality via a single entry point, the "main file" `auth/index.js`, to be used like this: + +```js +import {login, logout} from 'auth/index.js' +``` + +The idea is that outsiders, developers who use our package, should not meddle with its internal structure. They should not search for files inside our package folder. We export only what's necessary in `auth/index.js` and keep the rest hidden from prying eyes. + +Now, as the actual exported functionality is scattered among the package, we can gather and "re-export" it in `auth/index.js`: + +```js +// 📁 auth/index.js +import {login, logout} from './helpers.js'; +export {login, logout}; + +import User from './user.js'; +export {User}; + +import Githib from './providers/github.js'; +export {Github}; +... +``` + +"Re-exporting" is just a shorter notation for that: + +```js +// 📁 auth/index.js +export {login, logout} from './helpers.js'; +// or, to re-export all helpers, we could use: +// export * from './helpers.js'; + +export {default as User} from './user.js'; + +export {default as Githib} from './providers/github.js'; +... +``` + +````warn header="Re-exporting default is tricky" +Please note: `export User from './user.js'` won't work. It's actually a syntax error. To re-export the default export, we must mention it explicitly `{default as ...}`, like in the example above. + +Also, there's another oddity: `export * from './user.js'` re-exports only named exports, exluding the default one. Once again, we need to mention it explicitly. + +For instance, to re-export everything, two statements will be necessary: +```js +export * from './module.js'; // to re-export named exports +export {default} from './module.js'; // to re-export default +``` + +The default should be mentioned explicitly only when re-exporting: `import * as obj` works fine. It imports the default export as `obj.default`. So there's a slight asymmetry between import and export constructs here. +```` + +## Summary + +There are following types of `export`: + +- Before declaration: + - `export [default] class/function/variable ...` +- Standalone: + - `export {x [as y], ...}`. +- Re-export: + - `export {x [as y], ...} from "mod"` + - `export * from "mod"` (doesn't re-export default). + - `export {default [as y]} from "mod"` (re-export default). + +Import: + +- Named exports from module: + - `import {x [as y], ...} from "mod"` +- Default export: + - `import x from "mod"` + - `import {default as x} from "mod"` +- Everything: + - `import * as obj from "mod"` +- Only fetch/evalute the module, don't import: + - `import "mod"` + +We can put import/export statements below or after other code, that doesn't matter. + +So this is technically fine: +```js +sayHi(); + +import {sayHi} from './say.js'; // import at the end of the file +``` + +In practice imports are usually at the start of the file, but that's only for better convenience. + +**Please note that import/export statements don't work if inside `{...}`.** + +A conditional import, like this, won't work: +```js +if (something) { + import {sayHi} from "./say.js"; // Error: import must be at top level +} +``` + +...But what if we really need to import something conditionally? Or at the right time? Like, load a module upon request, when it's really needed? + +We'll see dynamic imports in the next chapter. diff --git a/1-js/12-modules/03-modules-dynamic-imports/article.md b/1-js/12-modules/03-modules-dynamic-imports/article.md new file mode 100644 index 000000000..513cdf897 --- /dev/null +++ b/1-js/12-modules/03-modules-dynamic-imports/article.md @@ -0,0 +1,54 @@ + +# Dynamic imports + +Export and import statements that we covered in previous chaters are called "static". + +What's because they are indeed static. The syntax is very strict. + +First, we can't dynamicaly generate any parameters of `import`. + +The module path must be a primitive string, can't be a function call. This won't work: + +```js +import ... from *!*getModuleName()*/!*; // Error, only from "string" is allowed +``` + +Second, we can't import conditionally or at run-time: + +```js +if(...) { + import ...; // Error, not allowed! +} + +{ + import ...; // Error, we can't put import in any block +} +``` + +That's because, import/export aim to provide a backbone for the code structure. That's a good thing, as code structure can be analyzed, modules can be gathered and bundled together, unused exports can be removed (tree-shaken). That's possible only because everything is fixed. + +But how do we import a module dynamically, on-demand? + +## The import() function + +The `import(module)` function can be called from anywhere. It returns a promise that resolves into a module object. + +The usage pattern looks like this: + +```js run +let modulePath = prompt("Module path?"); + +import(modulePath) + .then(obj => ) + .catch(err => ) +``` + +Or, we could use `let module = await import(modulePath)` if inside an async function. + +Like this: + +[codetabs src="say" current="index.html"] + +So, dynamic imports are very simple to use. + +Also, dynamic imports work in regular scripts, they don't require `script type="module"`. diff --git a/1-js/12-modules/03-modules-dynamic-imports/say.view/index.html b/1-js/12-modules/03-modules-dynamic-imports/say.view/index.html new file mode 100644 index 000000000..80909cf94 --- /dev/null +++ b/1-js/12-modules/03-modules-dynamic-imports/say.view/index.html @@ -0,0 +1,10 @@ + + + diff --git a/1-js/12-modules/03-modules-dynamic-imports/say.view/say.js b/1-js/12-modules/03-modules-dynamic-imports/say.view/say.js new file mode 100644 index 000000000..cff234b7c --- /dev/null +++ b/1-js/12-modules/03-modules-dynamic-imports/say.view/say.js @@ -0,0 +1,11 @@ +export function hi() { + alert(`Hello`); +} + +export function bye() { + alert(`Bye`); +} + +export default function() { + alert("Module loaded (export default)!"); +} diff --git a/1-js/12-modules/index.md b/1-js/12-modules/index.md new file mode 100644 index 000000000..78fb060e8 --- /dev/null +++ b/1-js/12-modules/index.md @@ -0,0 +1,2 @@ + +# Modules diff --git a/2-ui/1-document/01-browser-environment/windowObjects.png b/2-ui/1-document/01-browser-environment/windowObjects.png index 81803bd09..9db5fdcd0 100644 Binary files a/2-ui/1-document/01-browser-environment/windowObjects.png and b/2-ui/1-document/01-browser-environment/windowObjects.png differ diff --git a/2-ui/1-document/01-browser-environment/windowObjects@2x.png b/2-ui/1-document/01-browser-environment/windowObjects@2x.png index e6dae7c3d..1bd9025af 100644 Binary files a/2-ui/1-document/01-browser-environment/windowObjects@2x.png and b/2-ui/1-document/01-browser-environment/windowObjects@2x.png differ diff --git a/2-ui/1-document/02-dom-nodes/article.md b/2-ui/1-document/02-dom-nodes/article.md index a701fb0ce..6bb34ff8c 100644 --- a/2-ui/1-document/02-dom-nodes/article.md +++ b/2-ui/1-document/02-dom-nodes/article.md @@ -176,7 +176,7 @@ drawHtmlTree(node6, 'div.domtree', 690, 500); Here we see a new tree node type -- *comment node*, labeled as `#comment`. -We may think -- why a comment is added to the DOM? It doesn't affect the visual representation in any way. But there's a rule -- if something's in HTML, then it also must be in the DOM tree. +We may think -- why is a comment added to the DOM? It doesn't affect the visual representation in any way. But there's a rule -- if something's in HTML, then it also must be in the DOM tree. **Everything in HTML, even comments, becomes a part of the DOM.** diff --git a/2-ui/1-document/03-dom-navigation/article.md b/2-ui/1-document/03-dom-navigation/article.md index 976e595a2..f19b33072 100644 --- a/2-ui/1-document/03-dom-navigation/article.md +++ b/2-ui/1-document/03-dom-navigation/article.md @@ -7,11 +7,11 @@ libs: # Walking the DOM -The DOM allows to do anything with elements and their contents, but first we need to reach the corresponding DOM object, get it into a variable, and then we are able to modify it. +The DOM allows us to do anything with elements and their contents, but first we need to reach the corresponding DOM object, get it into a variable, and then we are able to modify it. All operations on the DOM start with the `document` object. From it we can access any node. -Here's a picture of links that allow to travel between DOM nodes: +Here's a picture of links that allow for travel between DOM nodes: ![](dom-links.png) @@ -155,9 +155,9 @@ The first thing is nice. The second is tolerable, because we can use `Array.from ```warn header="DOM collections are read-only" DOM collections, and even more -- *all* navigation properties listed in this chapter are read-only. -We can't replace a child by something else assigning `childNodes[i] = ...`. +We can't replace a child by something else by assigning `childNodes[i] = ...`. -Changing DOM needs other methods, we'll see them in the next chapter. +Changing DOM needs other methods. We will see them in the next chapter. ``` ```warn header="DOM collections are live" @@ -309,7 +309,7 @@ An example of usage: The specification: [tabular data](https://html.spec.whatwg.org/multipage/tables.html). -There are also additional navigation properties for HTML forms. We'll look at them later when start working with forms. +There are also additional navigation properties for HTML forms. We'll look at them later when we start working with forms. # Summary diff --git a/2-ui/1-document/03-dom-navigation/dom-links-elements.png b/2-ui/1-document/03-dom-navigation/dom-links-elements.png index f7eef5d1f..ad3446998 100644 Binary files a/2-ui/1-document/03-dom-navigation/dom-links-elements.png and b/2-ui/1-document/03-dom-navigation/dom-links-elements.png differ diff --git a/2-ui/1-document/03-dom-navigation/dom-links-elements@2x.png b/2-ui/1-document/03-dom-navigation/dom-links-elements@2x.png index cf4e220cf..62e8a0483 100644 Binary files a/2-ui/1-document/03-dom-navigation/dom-links-elements@2x.png and b/2-ui/1-document/03-dom-navigation/dom-links-elements@2x.png differ diff --git a/2-ui/1-document/03-dom-navigation/dom-links.png b/2-ui/1-document/03-dom-navigation/dom-links.png index 25b25b377..1ef2e96d0 100644 Binary files a/2-ui/1-document/03-dom-navigation/dom-links.png and b/2-ui/1-document/03-dom-navigation/dom-links.png differ diff --git a/2-ui/1-document/03-dom-navigation/dom-links@2x.png b/2-ui/1-document/03-dom-navigation/dom-links@2x.png index 84cd33d4e..6bfdb4b90 100644 Binary files a/2-ui/1-document/03-dom-navigation/dom-links@2x.png and b/2-ui/1-document/03-dom-navigation/dom-links@2x.png differ diff --git a/2-ui/1-document/05-basic-dom-node-properties/dom-class-hierarchy.png b/2-ui/1-document/05-basic-dom-node-properties/dom-class-hierarchy.png index e48064cce..fb2c55aa1 100644 Binary files a/2-ui/1-document/05-basic-dom-node-properties/dom-class-hierarchy.png and b/2-ui/1-document/05-basic-dom-node-properties/dom-class-hierarchy.png differ diff --git a/2-ui/1-document/05-basic-dom-node-properties/dom-class-hierarchy@2x.png b/2-ui/1-document/05-basic-dom-node-properties/dom-class-hierarchy@2x.png index 343f4890d..ece911997 100644 Binary files a/2-ui/1-document/05-basic-dom-node-properties/dom-class-hierarchy@2x.png and b/2-ui/1-document/05-basic-dom-node-properties/dom-class-hierarchy@2x.png differ diff --git a/2-ui/1-document/07-modifying-document/article.md b/2-ui/1-document/07-modifying-document/article.md index 9c38b3344..22907554f 100644 --- a/2-ui/1-document/07-modifying-document/article.md +++ b/2-ui/1-document/07-modifying-document/article.md @@ -341,7 +341,7 @@ To remove nodes, there are the following methods: `parentElem.removeChild(node)` -: Removes `elem` from `parentElem` (assuming it's a child). +: Removes `node` from `parentElem` (assuming it's a child). `node.remove()` : Removes the `node` from its place. diff --git a/2-ui/1-document/07-modifying-document/before-prepend-append-after.png b/2-ui/1-document/07-modifying-document/before-prepend-append-after.png index 5bff84d85..4db9d27a8 100644 Binary files a/2-ui/1-document/07-modifying-document/before-prepend-append-after.png and b/2-ui/1-document/07-modifying-document/before-prepend-append-after.png differ diff --git a/2-ui/1-document/07-modifying-document/before-prepend-append-after@2x.png b/2-ui/1-document/07-modifying-document/before-prepend-append-after@2x.png index 44c369ee6..c3c79b9bd 100644 Binary files a/2-ui/1-document/07-modifying-document/before-prepend-append-after@2x.png and b/2-ui/1-document/07-modifying-document/before-prepend-append-after@2x.png differ diff --git a/2-ui/1-document/07-modifying-document/insert-adjacent.png b/2-ui/1-document/07-modifying-document/insert-adjacent.png index 08063bc51..feb97f77c 100644 Binary files a/2-ui/1-document/07-modifying-document/insert-adjacent.png and b/2-ui/1-document/07-modifying-document/insert-adjacent.png differ diff --git a/2-ui/1-document/07-modifying-document/insert-adjacent@2x.png b/2-ui/1-document/07-modifying-document/insert-adjacent@2x.png index 60333ad1b..e89c7cf3d 100644 Binary files a/2-ui/1-document/07-modifying-document/insert-adjacent@2x.png and b/2-ui/1-document/07-modifying-document/insert-adjacent@2x.png differ diff --git a/2-ui/1-document/08-styles-and-classes/article.md b/2-ui/1-document/08-styles-and-classes/article.md index ed9db3032..5159c532d 100644 --- a/2-ui/1-document/08-styles-and-classes/article.md +++ b/2-ui/1-document/08-styles-and-classes/article.md @@ -116,7 +116,7 @@ Sometimes we want to assign a style property, and later remove it. For instance, to hide an element, we can set `elem.style.display = "none"`. -Then later we may want to remove the `style.display` as if it were not set. Instead of `delete elem.style.display` we should assign an empty line to it: `elem.style.display = ""`. +Then later we may want to remove the `style.display` as if it were not set. Instead of `delete elem.style.display` we should assign an empty string to it: `elem.style.display = ""`. ```js run // if we run this code, the "blinks" @@ -207,7 +207,7 @@ For instance, here `style` doesn't see the margin: ``` -...But what if we need, say, to increase the margin by 20px? We want the current value for the start. +...But what if we need, say, to increase the margin by 20px? We would want the current value of it. There's another method for that: `getComputedStyle`. @@ -281,7 +281,7 @@ Visited links may be colored using `:visited` CSS pseudoclass. But `getComputedStyle` does not give access to that color, because otherwise an arbitrary page could find out whether the user visited a link by creating it on the page and checking the styles. -JavaScript we may not see the styles applied by `:visited`. And also, there's a limitation in CSS that forbids to apply geometry-changing styles in `:visited`. That's to guarantee that there's no sideway for an evil page to test if a link was visited and hence to break the privacy. +JavaScript may not see the styles applied by `:visited`. And also, there's a limitation in CSS that forbids to apply geometry-changing styles in `:visited`. That's to guarantee that there's no sideway for an evil page to test if a link was visited and hence to break the privacy. ``` ## Summary diff --git a/2-ui/1-document/09-size-and-scroll/metric-all.png b/2-ui/1-document/09-size-and-scroll/metric-all.png index a6335bcd8..9e4ae9202 100644 Binary files a/2-ui/1-document/09-size-and-scroll/metric-all.png and b/2-ui/1-document/09-size-and-scroll/metric-all.png differ diff --git a/2-ui/1-document/09-size-and-scroll/metric-all@2x.png b/2-ui/1-document/09-size-and-scroll/metric-all@2x.png index e084c257b..5713afa18 100644 Binary files a/2-ui/1-document/09-size-and-scroll/metric-all@2x.png and b/2-ui/1-document/09-size-and-scroll/metric-all@2x.png differ diff --git a/2-ui/1-document/09-size-and-scroll/metric-client-width-height.png b/2-ui/1-document/09-size-and-scroll/metric-client-width-height.png index d10edb5f6..d6f5a49a5 100644 Binary files a/2-ui/1-document/09-size-and-scroll/metric-client-width-height.png and b/2-ui/1-document/09-size-and-scroll/metric-client-width-height.png differ diff --git a/2-ui/1-document/09-size-and-scroll/metric-client-width-height@2x.png b/2-ui/1-document/09-size-and-scroll/metric-client-width-height@2x.png index f31f483e4..89125b902 100644 Binary files a/2-ui/1-document/09-size-and-scroll/metric-client-width-height@2x.png and b/2-ui/1-document/09-size-and-scroll/metric-client-width-height@2x.png differ diff --git a/2-ui/1-document/09-size-and-scroll/metric-css.png b/2-ui/1-document/09-size-and-scroll/metric-css.png index a28bbab78..f9548a2d8 100644 Binary files a/2-ui/1-document/09-size-and-scroll/metric-css.png and b/2-ui/1-document/09-size-and-scroll/metric-css.png differ diff --git a/2-ui/1-document/09-size-and-scroll/metric-css@2x.png b/2-ui/1-document/09-size-and-scroll/metric-css@2x.png index e4fd7bb87..189fdc786 100644 Binary files a/2-ui/1-document/09-size-and-scroll/metric-css@2x.png and b/2-ui/1-document/09-size-and-scroll/metric-css@2x.png differ diff --git a/2-ui/1-document/09-size-and-scroll/metric-offset-parent.png b/2-ui/1-document/09-size-and-scroll/metric-offset-parent.png index a0fba50d2..08d86cd1d 100644 Binary files a/2-ui/1-document/09-size-and-scroll/metric-offset-parent.png and b/2-ui/1-document/09-size-and-scroll/metric-offset-parent.png differ diff --git a/2-ui/1-document/09-size-and-scroll/metric-offset-parent@2x.png b/2-ui/1-document/09-size-and-scroll/metric-offset-parent@2x.png index 125a91e15..7c1caa230 100644 Binary files a/2-ui/1-document/09-size-and-scroll/metric-offset-parent@2x.png and b/2-ui/1-document/09-size-and-scroll/metric-offset-parent@2x.png differ diff --git a/2-ui/1-document/09-size-and-scroll/metric-offset-width-height.png b/2-ui/1-document/09-size-and-scroll/metric-offset-width-height.png index f25957848..9e729645a 100644 Binary files a/2-ui/1-document/09-size-and-scroll/metric-offset-width-height.png and b/2-ui/1-document/09-size-and-scroll/metric-offset-width-height.png differ diff --git a/2-ui/1-document/09-size-and-scroll/metric-offset-width-height@2x.png b/2-ui/1-document/09-size-and-scroll/metric-offset-width-height@2x.png index 7bfb24c22..86f546b2b 100644 Binary files a/2-ui/1-document/09-size-and-scroll/metric-offset-width-height@2x.png and b/2-ui/1-document/09-size-and-scroll/metric-offset-width-height@2x.png differ diff --git a/2-ui/1-document/10-size-and-scroll-window/article.md b/2-ui/1-document/10-size-and-scroll-window/article.md index 4a62f56c6..b8c16a3c7 100644 --- a/2-ui/1-document/10-size-and-scroll-window/article.md +++ b/2-ui/1-document/10-size-and-scroll-window/article.md @@ -1,6 +1,6 @@ # Window sizes and scrolling -How to find out the width of the browser window? How to get the full height of the document, including the scrolled out part? How to scroll the page using JavaScript? +How to find out the width and height of the browser window? How to get the full width and height of the document, including the scrolled out part? How to scroll the page using JavaScript? From the DOM point of view, the root document element is `document.documentElement`. That element corresponds to `` and has geometry properties described in the [previous chapter](info:size-and-scroll). For some cases we can use it, but there are additional methods and peculiarities important enough to consider. @@ -44,7 +44,7 @@ Theoretically, as the root document element is `documentElement.clientWidth/Heig These properties work well for regular elements. But for the whole page these properties do not work as intended. In Chrome/Safari/Opera if there's no scroll, then `documentElement.scrollHeight` may be even less than `documentElement.clientHeight`! For regular elements that's a nonsense. -To have a reliable full window size, we should take the maximum of these properties: +To have a reliable result on the full document height, we should take the maximum of these properties: ```js run let scrollHeight = Math.max( @@ -96,7 +96,7 @@ It should work, but smells like cross-browser incompatibilities. Not good. Fortu ``` -- The method `scrollTo(pageX,pageY)` scrolls the page relative to the document top-left corner. It's like setting `scrollLeft/scrollTop`. +- The method `scrollTo(pageX,pageY)` scrolls the page relative to the document's top-left corner. It's like setting `scrollLeft/scrollTop`. To scroll to the very beginning, we can use `scrollTo(0,0)`. @@ -129,7 +129,7 @@ And this button scrolls the page to show it at the bottom: Sometimes we need to make the document "unscrollable". For instance, when we need to cover it with a large message requiring immediate attention, and we want the visitor to interact with that message, not with the document. -To make the document unscrollable, its enough to set `document.body.style.overflow = "hidden"`. The page will freeze on its current scroll. +To make the document unscrollable, it's enough to set `document.body.style.overflow = "hidden"`. The page will freeze on its current scroll. ```online Try it: @@ -145,7 +145,7 @@ We can use the same technique to "freeze" the scroll for other elements, not jus The drawback of the method is that the scrollbar disappears. If it occupied some space, then that space is now free, and the content "jumps" to fill it. -That looks a bit odd, but can be worked around if we compare `clientWidth` before and after the freeze, and if it increased (the scrollbar disappeared) then add `padding` to `document.body` in place of the scrollbar, to keep the content width same. +That looks a bit odd, but can be worked around if we compare `clientWidth` before and after the freeze, and if it increased (the scrollbar disappeared) then add `padding` to `document.body` in place of the scrollbar, to keep the content width the same. ## Summary diff --git a/2-ui/1-document/10-size-and-scroll-window/document-client-width-height.png b/2-ui/1-document/10-size-and-scroll-window/document-client-width-height.png index 76a45a7a7..a50065d9c 100644 Binary files a/2-ui/1-document/10-size-and-scroll-window/document-client-width-height.png and b/2-ui/1-document/10-size-and-scroll-window/document-client-width-height.png differ diff --git a/2-ui/1-document/10-size-and-scroll-window/document-client-width-height@2x.png b/2-ui/1-document/10-size-and-scroll-window/document-client-width-height@2x.png index 249db0edb..c3ed71ac1 100644 Binary files a/2-ui/1-document/10-size-and-scroll-window/document-client-width-height@2x.png and b/2-ui/1-document/10-size-and-scroll-window/document-client-width-height@2x.png differ diff --git a/2-ui/1-document/11-coordinates/article.md b/2-ui/1-document/11-coordinates/article.md index ac5978f12..61b5161eb 100644 --- a/2-ui/1-document/11-coordinates/article.md +++ b/2-ui/1-document/11-coordinates/article.md @@ -48,7 +48,7 @@ Also: - Coordinates may be decimal fractions. That's normal, internally browser uses them for calculations. We don't have to round them when setting to `style.position.left/top`, the browser is fine with fractions. - Coordinates may be negative. For instance, if the page is scrolled down and the top `elem` is now above the window. Then, `elem.getBoundingClientRect().top` is negative. -- Some browsers (like Chrome) provide additional properties (`width` and `height`) to `getBoundingClientRect` as the result. We can also get them by subtraction: `height=bottom-top`, `width=right-left`. +- Some browsers (like Chrome) provide additional properties, `width` and `height` of the element that invoked the method to `getBoundingClientRect` as the result. We can also get them by subtraction: `height=bottom-top`, `width=right-left`. ```warn header="Coordinates right/bottom are different from CSS properties" If we compare window coordinates versus CSS positioning, then there are obvious similarities to `position:fixed`. The positioning of an element is also relative to the viewport. diff --git a/2-ui/1-document/11-coordinates/coords.png b/2-ui/1-document/11-coordinates/coords.png index da4869fb9..7a080f68c 100644 Binary files a/2-ui/1-document/11-coordinates/coords.png and b/2-ui/1-document/11-coordinates/coords.png differ diff --git a/2-ui/1-document/11-coordinates/coords@2x.png b/2-ui/1-document/11-coordinates/coords@2x.png index c3469f4cd..1a94289be 100644 Binary files a/2-ui/1-document/11-coordinates/coords@2x.png and b/2-ui/1-document/11-coordinates/coords@2x.png differ diff --git a/2-ui/1-document/11-coordinates/document-window-coordinates-scroll.png b/2-ui/1-document/11-coordinates/document-window-coordinates-scroll.png index 9e4d9d5e9..b349ef6fa 100644 Binary files a/2-ui/1-document/11-coordinates/document-window-coordinates-scroll.png and b/2-ui/1-document/11-coordinates/document-window-coordinates-scroll.png differ diff --git a/2-ui/1-document/11-coordinates/document-window-coordinates-scroll@2x.png b/2-ui/1-document/11-coordinates/document-window-coordinates-scroll@2x.png index 52e555c49..5dbbc4cb8 100644 Binary files a/2-ui/1-document/11-coordinates/document-window-coordinates-scroll@2x.png and b/2-ui/1-document/11-coordinates/document-window-coordinates-scroll@2x.png differ diff --git a/2-ui/1-document/11-coordinates/document-window-coordinates-zero.png b/2-ui/1-document/11-coordinates/document-window-coordinates-zero.png index 3624196b0..4f089f360 100644 Binary files a/2-ui/1-document/11-coordinates/document-window-coordinates-zero.png and b/2-ui/1-document/11-coordinates/document-window-coordinates-zero.png differ diff --git a/2-ui/1-document/11-coordinates/document-window-coordinates-zero@2x.png b/2-ui/1-document/11-coordinates/document-window-coordinates-zero@2x.png index 83f31950c..2f33e35ff 100644 Binary files a/2-ui/1-document/11-coordinates/document-window-coordinates-zero@2x.png and b/2-ui/1-document/11-coordinates/document-window-coordinates-zero@2x.png differ diff --git a/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/move-ball-coords.png b/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/move-ball-coords.png index ca2f49edb..73b12aacf 100644 Binary files a/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/move-ball-coords.png and b/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/move-ball-coords.png differ diff --git a/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/move-ball-coords@2x.png b/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/move-ball-coords@2x.png index b4c4d3ef2..7bd13439e 100644 Binary files a/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/move-ball-coords@2x.png and b/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/move-ball-coords@2x.png differ diff --git a/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel1.png b/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel1.png index b58ac0a66..cf04efa93 100644 Binary files a/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel1.png and b/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel1.png differ diff --git a/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel1@2x.png b/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel1@2x.png index fe6a0badd..2b9ffc83a 100644 Binary files a/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel1@2x.png and b/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel1@2x.png differ diff --git a/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel2.png b/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel2.png index 351ead9c4..d81ea7501 100644 Binary files a/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel2.png and b/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel2.png differ diff --git a/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel2@2x.png b/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel2@2x.png index 05dbc1adf..1f49b6289 100644 Binary files a/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel2@2x.png and b/2-ui/2-events/01-introduction-browser-events/07-carousel/carousel2@2x.png differ diff --git a/2-ui/2-events/02-bubbling-and-capturing/article.md b/2-ui/2-events/02-bubbling-and-capturing/article.md index 287f74f2a..191b27393 100644 --- a/2-ui/2-events/02-bubbling-and-capturing/article.md +++ b/2-ui/2-events/02-bubbling-and-capturing/article.md @@ -108,7 +108,7 @@ Sometimes `event.stopPropagation()` creates hidden pitfalls that later may becom For instance: -1. We create a nested menu. Each submenu handles clicks on its elements and calls `stopPropagation` so that outer menu don't trigger. +1. We create a nested menu. Each submenu handles clicks on its elements and calls `stopPropagation` so that the outer menu won't trigger. 2. Later we decide to catch clicks on the whole window, to track users' behavior (where people click). Some analytic systems do that. Usually the code uses `document.addEventListener('click'…)` to catch all clicks. 3. Our analytic won't work over the area where clicks are stopped by `stopPropagation`. We've got a "dead zone". diff --git a/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling.png b/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling.png index a4f4fae51..e6f01b463 100644 Binary files a/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling.png and b/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling.png differ diff --git a/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling@2x.png b/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling@2x.png index e3a070cb8..f9096a6c8 100644 Binary files a/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling@2x.png and b/2-ui/2-events/02-bubbling-and-capturing/event-order-bubbling@2x.png differ diff --git a/2-ui/2-events/02-bubbling-and-capturing/eventflow.png b/2-ui/2-events/02-bubbling-and-capturing/eventflow.png index 95c5c08e0..9c456d8e8 100644 Binary files a/2-ui/2-events/02-bubbling-and-capturing/eventflow.png and b/2-ui/2-events/02-bubbling-and-capturing/eventflow.png differ diff --git a/2-ui/2-events/02-bubbling-and-capturing/eventflow@2x.png b/2-ui/2-events/02-bubbling-and-capturing/eventflow@2x.png index d52c4f70c..2a7461fa3 100644 Binary files a/2-ui/2-events/02-bubbling-and-capturing/eventflow@2x.png and b/2-ui/2-events/02-bubbling-and-capturing/eventflow@2x.png differ diff --git a/2-ui/2-events/03-event-delegation/bagua-bubble.png b/2-ui/2-events/03-event-delegation/bagua-bubble.png index f0433aeb1..7cf89818b 100644 Binary files a/2-ui/2-events/03-event-delegation/bagua-bubble.png and b/2-ui/2-events/03-event-delegation/bagua-bubble.png differ diff --git a/2-ui/2-events/03-event-delegation/bagua-bubble@2x.png b/2-ui/2-events/03-event-delegation/bagua-bubble@2x.png index 8cc5ca913..c22075602 100644 Binary files a/2-ui/2-events/03-event-delegation/bagua-bubble@2x.png and b/2-ui/2-events/03-event-delegation/bagua-bubble@2x.png differ diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md index 30627f3ca..f60d7e63e 100644 --- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md +++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md @@ -50,7 +50,7 @@ If the mouse moves very fast from `#FROM` to `#TO` elements as painted above, th In practice that's helpful, because if there may be many intermediate elements. We don't really want to process in and out of each one. -From the other side, we should keep in mind that we can't assume that the mouse slowly moves from one event to another. No, it can "jump". +On the other hand, we should keep in mind that we can't assume that the mouse slowly moves from one event to another. No, it can "jump". In particular it's possible that the cursor jumps right inside the middle of the page from out of the window. And `relatedTarget=null`, because it came from "nowhere": diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside.png index ea5723307..b42b4a598 100644 Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside.png differ diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside@2x.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside@2x.png index 6a17ca99f..7dff0fac7 100644 Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside@2x.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside@2x.png differ diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems.png index babbea502..7ce49c9ba 100644 Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems.png differ diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems@2x.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems@2x.png index e61891a5a..2ba6772a0 100644 Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems@2x.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems@2x.png differ diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout.png index e82adf50e..d22e715c9 100644 Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout.png differ diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout@2x.png b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout@2x.png index b1c567e97..c234b4628 100644 Binary files a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout@2x.png and b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout@2x.png differ diff --git a/2-ui/4-forms-controls/1-form-elements/form-navigation.png b/2-ui/4-forms-controls/1-form-elements/form-navigation.png index 5d00632b2..458ab9eb0 100644 Binary files a/2-ui/4-forms-controls/1-form-elements/form-navigation.png and b/2-ui/4-forms-controls/1-form-elements/form-navigation.png differ diff --git a/2-ui/4-forms-controls/1-form-elements/form-navigation@2x.png b/2-ui/4-forms-controls/1-form-elements/form-navigation@2x.png index 1997b2b36..264803ebb 100644 Binary files a/2-ui/4-forms-controls/1-form-elements/form-navigation@2x.png and b/2-ui/4-forms-controls/1-form-elements/form-navigation@2x.png differ diff --git a/2-ui/4-forms-controls/2-focus-blur/3-editable-div/task.md b/2-ui/4-forms-controls/2-focus-blur/3-editable-div/task.md index 2a5a6a9b2..8e45bfa86 100644 --- a/2-ui/4-forms-controls/2-focus-blur/3-editable-div/task.md +++ b/2-ui/4-forms-controls/2-focus-blur/3-editable-div/task.md @@ -8,6 +8,6 @@ Create a `
` that turns into `