diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md index 1e2e97d7..10bd54fe 100644 --- a/1-js/01-getting-started/1-intro/article.md +++ b/1-js/01-getting-started/1-intro/article.md @@ -108,7 +108,7 @@ Modern tools make the transpilation very fast and transparent, actually allowing Examples of such languages: -- [CoffeeScript](http://coffeescript.org/) is a "syntax sugar" for JavaScript, it introduces shorter syntax, allowing to write more precise and clear code. Usually Ruby devs like it. +- [CoffeeScript](http://coffeescript.org/) is a "syntactic sugar" for JavaScript, it introduces shorter syntax, allowing to write more precise and clear code. Usually Ruby devs like it. - [TypeScript](http://www.typescriptlang.org/) is concentrated on adding "strict data typing", to simplify development and support of complex systems. It is developed by Microsoft. - [Dart](https://www.dartlang.org/) is a standalone language that has its own engine that runs in non-browser environments (like mobile apps). It was initially offered by Google as a replacement for JavaScript, but as of now, browsers require it to be transpiled to JavaScript just like the ones above. diff --git a/1-js/05-data-types/05-array-methods/10-average-age/solution.md b/1-js/05-data-types/05-array-methods/10-average-age/solution.md index 5e19fb5a..f5d4df93 100644 --- a/1-js/05-data-types/05-array-methods/10-average-age/solution.md +++ b/1-js/05-data-types/05-array-methods/10-average-age/solution.md @@ -3,9 +3,9 @@ function getAverageAge(users) { return users.reduce((prev, user) => prev + user.age, 0) / users.length; } -let john = { name: "John", age: 25 } -let pete = { name: "Pete", age: 30 } -let mary = { name: "Mary", age: 29 } +let john = { name: "John", age: 25 }; +let pete = { name: "Pete", age: 30 }; +let mary = { name: "Mary", age: 29 }; let arr = [ john, pete, mary ]; diff --git a/1-js/05-data-types/05-array-methods/10-average-age/task.md b/1-js/05-data-types/05-array-methods/10-average-age/task.md index ccb2142d..a991c156 100644 --- a/1-js/05-data-types/05-array-methods/10-average-age/task.md +++ b/1-js/05-data-types/05-array-methods/10-average-age/task.md @@ -11,12 +11,12 @@ The formula for the average is `(age1 + age2 + ... + ageN) / N`. For instance: ```js no-beautify -let john = { name: "John", age: 25 } -let pete = { name: "Pete", age: 30 } -let mary = { name: "Mary", age: 29 } +let john = { name: "John", age: 25 }; +let pete = { name: "Pete", age: 30 }; +let mary = { name: "Mary", age: 29 }; let arr = [ john, pete, mary ]; -alert( getAverageAge(arr) ); // (25+30+29)/3 = 28 +alert( getAverageAge(arr) ); // (25 + 30 + 29) / 3 = 28 ``` diff --git a/1-js/05-data-types/05-array-methods/2-filter-range/task.md b/1-js/05-data-types/05-array-methods/2-filter-range/task.md index fb6f06ee..18b2c1d9 100644 --- a/1-js/05-data-types/05-array-methods/2-filter-range/task.md +++ b/1-js/05-data-types/05-array-methods/2-filter-range/task.md @@ -2,7 +2,7 @@ importance: 4 --- -# Filter "in place" +# Filter range Write a function `filterRange(arr, a, b)` that gets an array `arr`, looks for elements between `a` and `b` in it and returns an array of them. diff --git a/1-js/05-data-types/05-array-methods/4-sort-back/solution.md b/1-js/05-data-types/05-array-methods/4-sort-back/solution.md index 5a9f076b..cdf13351 100644 --- a/1-js/05-data-types/05-array-methods/4-sort-back/solution.md +++ b/1-js/05-data-types/05-array-methods/4-sort-back/solution.md @@ -3,7 +3,7 @@ ```js run let arr = [5, 2, 1, -10, 8]; -arr.sort((a,b) => b - a); +arr.sort((a, b) => b - a); alert( arr ); ``` diff --git a/1-js/05-data-types/05-array-methods/7-map-objects/solution.md b/1-js/05-data-types/05-array-methods/7-map-objects/solution.md index 9085b631..5d8bf4a1 100644 --- a/1-js/05-data-types/05-array-methods/7-map-objects/solution.md +++ b/1-js/05-data-types/05-array-methods/7-map-objects/solution.md @@ -21,8 +21,8 @@ usersMapped = [ ] */ -alert( usersMapped[0].id ) // 1 -alert( usersMapped[0].fullName ) // John Smith +alert( usersMapped[0].id ); // 1 +alert( usersMapped[0].fullName ); // John Smith ``` Please note that in for the arrow functions we need to use additional brackets. 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 2c7c5181..8d56db9d 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 @@ -12,6 +12,6 @@ let arr = [ john, pete, mary ]; sortByName(arr); // now sorted is: [john, mary, pete] -alert(arr[1].name) // Mary +alert(arr[1].name); // Mary ``` 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 e423f57a..8a3f5a97 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 @@ -9,15 +9,15 @@ Write the function `sortByName(users)` that gets an array of objects with proper For instance: ```js no-beautify -let john = { name: "John", age: 25 } -let pete = { name: "Pete", age: 30 } -let mary = { name: "Mary", age: 28 } +let john = { name: "John", age: 25 }; +let pete = { name: "Pete", age: 30 }; +let mary = { name: "Mary", age: 28 }; let arr = [ john, pete, mary ]; sortByName(arr); // now: [john, mary, pete] -alert(arr[1].name) // Mary +alert(arr[1].name); // Mary ``` diff --git a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md index 12cf7551..a43715db 100644 --- a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md +++ b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md @@ -12,7 +12,7 @@ shuffle(arr); alert(arr); ``` -That somewhat works, because `Math.random()-0.5` is a random number that may be positive or negative, so the sorting function reorders elements randomly. +That somewhat works, because `Math.random() - 0.5` is a random number that may be positive or negative, so the sorting function reorders elements randomly. But because the sorting function is not meant to be used this way, not all permutations have the same probability. @@ -33,14 +33,14 @@ let count = { '312': 0 }; -for(let i = 0; i < 1000000; i++) { +for (let i = 0; i < 1000000; i++) { let array = [1, 2, 3]; shuffle(array); count[array.join('')]++; } // show counts of all possible permutations -for(let key in count) { +for (let key in count) { alert(`${key}: ${count[key]}`); } ``` @@ -66,8 +66,8 @@ There are other good ways to do the task. For instance, there's a great algorith ```js function shuffle(array) { - for(let i = array.length - 1; i > 0; i--) { - let j = Math.floor(Math.random() * (i+1)); // random index from 0 to i + for (let i = array.length - 1; i > 0; i--) { + let j = Math.floor(Math.random() * (i + 1)); // random index from 0 to i [array[i], array[j]] = [array[j], array[i]]; // swap elements } } @@ -77,8 +77,8 @@ Let's test it the same way: ```js run function shuffle(array) { - for(let i = array.length - 1; i > 0; i--) { - let j = Math.floor(Math.random() * (i+1)); + for (let i = array.length - 1; i > 0; i--) { + let j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } } @@ -93,14 +93,14 @@ let count = { '312': 0 }; -for(let i = 0; i < 1000000; i++) { +for (let i = 0; i < 1000000; i++) { let array = [1, 2, 3]; shuffle(array); count[array.join('')]++; } // show counts of all possible permutations -for(let key in count) { +for (let key in count) { alert(`${key}: ${count[key]}`); } ``` diff --git a/1-js/05-data-types/06-iterable/article.md b/1-js/05-data-types/06-iterable/article.md index cd6c074b..1ccbaea0 100644 --- a/1-js/05-data-types/06-iterable/article.md +++ b/1-js/05-data-types/06-iterable/article.md @@ -121,7 +121,7 @@ Arrays and strings are most widely used built-in iterables. For a string, `for..of` loops over its characters: ```js run -for(let char of "test") { +for (let char of "test") { alert( char ); // t, then e, then s, then t } ``` @@ -130,8 +130,8 @@ And it works right with surrogate pairs! ```js run let str = '𝒳😂'; -for(let char of str) { - alert(char); // 𝒳, and then 😂 +for (let char of str) { + alert( char ); // 𝒳, and then 😂 } ``` @@ -139,7 +139,7 @@ for(let char of str) { Normally, internals of iterables are hidden from the external code. There's a `for..of` loop, that works, that's all it needs to know. -But to understand things a little bit more deeper let's see how to create an iterator explicitly. +But to understand things a little bit deeper let's see how to create an iterator explicitly. We'll iterate over a string the same way as `for..of`, but with direct calls. This code gets a string iterator and calls it "manually": @@ -151,7 +151,7 @@ let str = "Hello"; let iterator = str[Symbol.iterator](); -while(true) { +while (true) { let result = iterator.next(); if (result.done) break; alert(result.value); // outputs characters one by one @@ -184,7 +184,7 @@ let arrayLike = { // has indexes and length => array-like *!* // Error (no Symbol.iterator) -for(let item of arrayLike) {} +for (let item of arrayLike) {} */!* ``` @@ -258,7 +258,7 @@ Technically here it does the same as: let str = '𝒳😂'; let chars = []; // Array.from internally does the same loop -for(let char of str) { +for (let char of str) { chars.push(char); } 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 f95b41aa..dacb4285 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 @@ -15,7 +15,7 @@ We'll use the letter-sorted variants as map keys to store only one value per eac function aclean(arr) { let map = new Map(); - for(let word of arr) { + for (let word of arr) { // split the word by letters, sort them and join back *!* let sorted = word.toLowerCase().split('').sort().join(''); // (*) 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 0769f57d..e3e28f4f 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 @@ -137,17 +137,17 @@ let recipeMap = new Map([ ]); // iterate over keys (vegetables) -for(let vegetable of recipeMap.keys()) { +for (let vegetable of recipeMap.keys()) { alert(vegetable); // cucumber, tomateos, onion } // iterate over values (amounts) -for(let amount of recipeMap.values()) { +for (let amount of recipeMap.values()) { alert(amount); // 500, 350, 50 } // iterate over [key, value] entries -for(let entry of recipeMap) { // the same as of recipeMap.entries() +for (let entry of recipeMap) { // the same as of recipeMap.entries() alert(entry); // cucumber,500 (and so on) } ``` @@ -199,7 +199,7 @@ set.add(mary); // set keeps only unique values alert( set.size ); // 3 -for(let user of set) { +for (let user of set) { alert(user.name); // John (then Pete and Mary) } ``` @@ -213,7 +213,7 @@ We can loop over a set either with `for..of` or using `forEach`: ```js run let set = new Set(["oranges", "apples", "bananas"]); -for(let value of set) alert(value); +for (let value of set) alert(value); // the same with forEach: set.forEach((value, valueAgain, set) => { @@ -332,7 +332,7 @@ That's useful for situations when we have a main storage for the objects somewhe Let's see an example. -For instance, we have a code that keeps a visit count for each user. The information is stored in a map: a user is the key and the visit count is the value. When a user leaves, we don't want to store his visit count any more. +For instance, we have a code that keeps a visit count for each user. The information is stored in a map: a user is the key and the visit count is the value. When a user leaves, we don't want to store his visit count anymore. One way would be to keep track of leaving users and clean up the storage manually: @@ -345,7 +345,7 @@ let visitsCountMap = new Map(); // john is the key for the map visitsCountMap.set(john, 123); -// now john leaves us, we don't need him any more +// now john leaves us, we don't need him anymore john = null; *!* @@ -364,7 +364,7 @@ let visitsCountMap = new WeakMap(); visitsCountMap.set(john, 123); -// now john leaves us, we don't need him any more +// now john leaves us, we don't need him anymore john = null; // there are no references except WeakMap, @@ -408,7 +408,7 @@ The most notable limitation of `WeakMap` and `WeakSet` is the absence of iterati ## Summary -- `Map` -- is a a collection of keyed values. +- `Map` -- is a collection of keyed values. The differences from a regular `Object`: @@ -421,12 +421,12 @@ The most notable limitation of `WeakMap` and `WeakSet` is the absence of iterati - Unlike an array, does not allow to reorder elements. - Keeps the insertion order. -- `WeakMap` -- a variant of `Map` that allows only objects as keys and removes them once they become unaccessible by other means. +- `WeakMap` -- a variant of `Map` that allows only objects as keys and removes them once they become inaccessible by other means. - It does not support operations on the structure as a whole: no `size`, no `clear()`, no iterations. -- `WeakSet` -- is a variant of `Set` that only stores objects and removes them once they become unaccessible by other means. +- `WeakSet` -- is a variant of `Set` that only stores objects and removes them once they become inaccessible by other means. - Also does not support `size/clear()` and iterations. -`WeakMap` and `WeakSet` are used as "secondary" data structures in additional to the "main" object storage. Once the object is removed from the main storage, so it only stays in `WeakMap/WeakSet`, they clean up aumatically. +`WeakMap` and `WeakSet` are used as "secondary" data structures in addition to the "main" object storage. Once the object is removed from the main storage, so it only stays in `WeakMap/WeakSet`, they clean up automatically. diff --git a/1-js/05-data-types/08-keys-values-entries/article.md b/1-js/05-data-types/08-keys-values-entries/article.md index a33f17e5..50ba91ce 100644 --- a/1-js/05-data-types/08-keys-values-entries/article.md +++ b/1-js/05-data-types/08-keys-values-entries/article.md @@ -58,7 +58,7 @@ let user = { }; // loop over values -for(let value of Object.values(user)) { +for (let value of Object.values(user)) { alert(value); // John, then 30 } ``` 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 55df9399..a1fb7d54 100644 --- a/1-js/05-data-types/09-destructuring-assignment/article.md +++ b/1-js/05-data-types/09-destructuring-assignment/article.md @@ -99,7 +99,7 @@ let user = { // loop over keys-and-values *!* -for(let [key, value] of Object.entries(user)) { +for (let [key, value] of Object.entries(user)) { */!* alert(`${key}:${value}`); // name:John, then age:30 } @@ -113,7 +113,7 @@ user.set("name", "John"); user.set("age", "30"); *!* -for(let [key, value] of user.entries()) { +for (let [key, value] of user.entries()) { */!* alert(`${key}:${value}`); // name:John, then age:30 } @@ -136,7 +136,7 @@ alert(rest.length); // 2 */!* ``` -The value of `rest` is the array of the remaining array elements. We can use any other variable name in place of `rest`, just make sure it has three dots before it and goes last in the destructuring assignmemnt. +The value of `rest` is the array of the remaining array elements. We can use any other variable name in place of `rest`, just make sure it has three dots before it and goes last in the destructuring assignment. ### Default values @@ -155,7 +155,7 @@ If we want a "default" value to replace the missing one, we can provide it using ```js run *!* // default values -let [name="Guest", surname="Anonymous"] = ["Julius"]; +let [name = "Guest", surname = "Anonymous"] = ["Julius"]; */!* alert(name); // Julius (from array) @@ -168,7 +168,7 @@ For instance, here we use the `prompt` function for two defaults. But it will ru ```js run // runs only prompt for surname -let [name=prompt('name?'), surname=prompt('surname?')] = ["Julius"]; +let [name = prompt('name?'), surname = prompt('surname?')] = ["Julius"]; alert(name); // Julius (from array) alert(surname); // whatever prompt gets @@ -248,7 +248,7 @@ let options = { }; *!* -let {width=100, height=200, title} = options; +let {width = 100, height = 200, title} = options; */!* alert(title); // Menu @@ -266,7 +266,7 @@ let options = { }; *!* -let {width=prompt("width?"), title=prompt("title?")} = options; +let {width = prompt("width?"), title = prompt("title?")} = options; */!* alert(title); // Menu @@ -281,7 +281,7 @@ let options = { }; *!* -let {width:w=100, height:h=200, title} = options; +let {width: w = 100, height: h = 200, title} = options; */!* alert(title); // Menu @@ -434,7 +434,7 @@ let options = { function showMenu(*!*{title = "Untitled", width = 200, height = 100, items = []}*/!*) { // title, items – taken from options, // width, height – defaults used - alert( title + ' ' + width + ' ' + height ); // My Menu 100 200 + alert( `${title} ${width} ${height}` ); // My Menu 200 100 alert( items ); // Item1, Item2 } @@ -452,12 +452,12 @@ let options = { *!* function showMenu({ title = "Untitled", - width:w = 100, // width goes to w - height:h = 200, // height goes to h + width: w = 100, // width goes to w + height: h = 200, // height goes to h items: [item1, item2] // items first element goes to item1, second to item2 }) { */!* - alert( title + ' ' + w + ' ' + h ); // My Menu 100 200 + alert( `${title} ${w} ${h}` ); // My Menu 100 200 alert( item1 ); // Item1 alert( item2 ); // Item2 } @@ -487,8 +487,8 @@ We can fix this by making `{}` the default value for the whole destructuring thi ```js run // simplified parameters a bit for clarity -function showMenu(*!*{ title="Menu", width=100, height=200 } = {}*/!*) { - alert( title + ' ' + width + ' ' + height ); +function showMenu(*!*{ title = "Menu", width = 100, height = 200 } = {}*/!*) { + alert( `${title} ${width} ${height}` ); } showMenu(); // Menu 100 200 diff --git a/1-js/05-data-types/10-date/article.md b/1-js/05-data-types/10-date/article.md index c025aaa4..becd9ac1 100644 --- a/1-js/05-data-types/10-date/article.md +++ b/1-js/05-data-types/10-date/article.md @@ -100,7 +100,7 @@ There are also their UTC-counterparts, that return day, month, year and so on fo If your local time zone is shifted relative to UTC, then the code below shows different hours: ```js run -// currend date +// current date let date = new Date(); // the hour in your current time zone @@ -208,7 +208,7 @@ let date = new Date(); alert(+date); // the number of milliseconds, same as date.getTime() ``` -The important side effect: dates can be substracted, the result is their difference in ms. +The important side effect: dates can be subtracted, the result is their difference in ms. That can be used for time measurements: @@ -251,7 +251,7 @@ for (let i = 0; i < 100000; i++) { let end = Date.now(); // done */!* -alert( `The loop took ${end - start} ms` ); // substract numbers, not dates +alert( `The loop took ${end - start} ms` ); // subtract numbers, not dates ``` ## Benchmarking @@ -262,7 +262,7 @@ For instance, let's measure two functions that calculate the difference between ```js // we have date1 and date2, which function faster returns their difference in ms? -function diffSubstract(date1, date2) { +function diffSubtract(date1, date2) { return date2 - date1; } @@ -281,7 +281,7 @@ The first idea may be to run them many times in a row and measure the time diffe Let's measure: ```js run -function diffSubstract(date1, date2) { +function diffSubtract(date1, date2) { return date2 - date1; } @@ -298,7 +298,7 @@ function bench(f) { return Date.now() - start; } -alert( 'Time of diffSubstract: ' + bench(diffSubstract) + 'ms' ); +alert( 'Time of diffSubtract: ' + bench(diffSubtract) + 'ms' ); alert( 'Time of diffGetTime: ' + bench(diffGetTime) + 'ms' ); ``` @@ -306,7 +306,7 @@ Wow! Using `getTime()` is so much faster! That's because there's no type convers Okay, we have something. But that's not a good benchmark yet. -Imagine that at the time of running `bench(diffSubstract)` CPU was doing something in parallel, and it was taking resources. And by the time of running `bench(diffGetTime)` the work has finished. +Imagine that at the time of running `bench(diffSubtract)` CPU was doing something in parallel, and it was taking resources. And by the time of running `bench(diffGetTime)` the work has finished. A pretty real scenario for a modern multi-process OS. @@ -317,7 +317,7 @@ As a result, the first benchmark will have less CPU resources than the second. T Here's the code example: ```js run -function diffSubstract(date1, date2) { +function diffSubtract(date1, date2) { return date2 - date1; } @@ -340,12 +340,12 @@ let time2 = 0; *!* // run bench(upperSlice) and bench(upperLoop) each 10 times alternating for (let i = 0; i < 10; i++) { - time1 += bench(diffSubstract); + time1 += bench(diffSubtract); time2 += bench(diffGetTime); } */!* -alert( 'Total time for diffSubstract: ' + time1 ); +alert( 'Total time for diffSubtract: ' + time1 ); alert( 'Total time for diffGetTime: ' + time2 ); ``` @@ -353,12 +353,12 @@ Modern JavaScript engines start applying advanced optimizations only to "hot cod ```js // added for "heating up" prior to the main loop -bench(diffSubstract); +bench(diffSubtract); bench(diffGetTime); // now benchmark for (let i = 0; i < 10; i++) { - time1 += bench(diffSubstract); + time1 += bench(diffSubtract); time2 += bench(diffGetTime); } ``` @@ -405,8 +405,8 @@ alert(date); - Date and time in JavaScript are represented with the [Date](mdn:js/Date) object. We can't create "only date" or "only time": `Date` objects always carry both. - Months are counted from zero (yes, January is a zero month). - Days of week in `getDay()` are also counted from zero (that's Sunday). -- `Date` auto-corrects itself when out-of-range components are set. Good for adding/substracting days/months/hours. -- Dates can be substracted, giving their difference in milliseconds. That's because a `Date` becomes the timestamp if converted to a number. +- `Date` auto-corrects itself when out-of-range components are set. Good for adding/subtracting days/months/hours. +- Dates can be subtracted, giving their difference in milliseconds. That's because a `Date` becomes the timestamp when converted to a number. - Use `Date.now()` to get the current timestamp fast. Note that unlike many other systems, timestamps in JavaScript are in milliseconds, not in seconds. @@ -417,7 +417,7 @@ Also, sometimes we need more precise time measurements. JavaScript itself does n alert(`Loading started ${performance.now()}ms ago`); // Something like: "Loading started 34731.26000000001ms ago" // .26 is microseconds (260 microseconds) -// more than 3 digits after the decimal point are precision errors, but only 3 first are correct +// more than 3 digits after the decimal point are precision errors, but only the first 3 are correct ``` Node.JS has `microtime` module and other ways. Technically, any device and environment allows to get more precision, it's just not in `Date`. diff --git a/1-js/06-advanced-functions/01-recursion/article.md b/1-js/06-advanced-functions/01-recursion/article.md index 1dedd228..466ce26b 100644 --- a/1-js/06-advanced-functions/01-recursion/article.md +++ b/1-js/06-advanced-functions/01-recursion/article.md @@ -31,7 +31,7 @@ There are two ways to implement it. let result = 1; // multiply result by x n times in the loop - for(let i = 0; i < n; i++) { + for (let i = 0; i < n; i++) { result *= x; } @@ -67,8 +67,8 @@ pow(x, n) = else = x * pow(x, n - 1) ``` -1. If `n==1`, then everything is trivial. It is called *the base* of recursion, because it immediately produces the obvious result: `pow(x, 1)` equals `x`. -2. Otherwise, we can represent `pow(x, n)` as `x * pow(x, n-1)`. In maths, one would write xn = x * xn-1. This is called *a recursive step*: we transform the task into a simpler action (multiplication by `x`) and a simpler call of the same task (`pow` with lower `n`). Next steps simplify it further and further untill `n` reaches `1`. +1. If `n == 1`, then everything is trivial. It is called *the base* of recursion, because it immediately produces the obvious result: `pow(x, 1)` equals `x`. +2. Otherwise, we can represent `pow(x, n)` as `x * pow(x, n - 1)`. In maths, one would write xn = x * xn-1. This is called *a recursive step*: we transform the task into a simpler action (multiplication by `x`) and a simpler call of the same task (`pow` with lower `n`). Next steps simplify it further and further until `n` reaches `1`. We can also say that `pow` *recursively calls itself* till `n == 1`. @@ -91,7 +91,7 @@ Here we can rewrite the same using the ternary `?` operator instead of `if` to m ```js run function pow(x, n) { - return (n == 1) ? x : (x * pow(x, n-1)); + return (n == 1) ? x : (x * pow(x, n - 1)); } ``` ```` @@ -134,7 +134,7 @@ We can sketch it as: -That's when the function starts to execute. The condition `n == 1` is falsy, so the flow continues into the second branch of `if`: +That's when the function starts to execute. The condition `n == 1` is false, so the flow continues into the second branch of `if`: ```js run function pow(x, n) { @@ -160,7 +160,7 @@ The variables are same, but the line changes, so the context is now: -To calculate `x*pow(x, n-1)`, we need to make a subcall of `pow` with new arguments `pow(2, 2)`. +To calculate `x * pow(x, n - 1)`, we need to make a subcall of `pow` with new arguments `pow(2, 2)`. ### pow(2, 2) @@ -230,7 +230,7 @@ function pow(x, n) { There are no more nested calls, so the function finishes, returning `2`. -As the function finishes, its execution context is not needed any more, so it's removed from the memory. The previous one is restored off the top of the stack: +As the function finishes, its execution context is not needed anymore, so it's removed from the memory. The previous one is restored off the top of the stack: -The execution of `pow(2, 2)` is resumed. It has the result of the subcall `pow(2, 1)`, so it also can finish the evaluation of `x * pow(x, n-1)`, returning `4`. +The execution of `pow(2, 2)` is resumed. It has the result of the subcall `pow(2, 1)`, so it also can finish the evaluation of `x * pow(x, n - 1)`, returning `4`. Then the previous context is restored: @@ -269,7 +269,7 @@ A loop-based algorithm is more memory-saving: function pow(x, n) { let result = 1; - for(let i = 0; i < n; i++) { + for (let i = 0; i < n; i++) { result *= x; } @@ -360,7 +360,7 @@ function sumSalaries(department) { return department.reduce((prev, current) => prev + current.salary, 0); // sum the array } else { // case (2) let sum = 0; - for(let subdep of Object.values(department)) { + for (let subdep of Object.values(department)) { sum += sumSalaries(subdep); // recursively call for subdepartments, sum the results } return sum; @@ -395,7 +395,7 @@ A company *department* is: - Either an array of people. - Or an object with *departments*. -For web-developers there are much better known examples: HTML and XML documents. +For web-developers there are much better-known examples: HTML and XML documents. In the HTML document, an *HTML-tag* may contain a list of: - Text pieces. diff --git a/1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md b/1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md index eaa42ab9..0788860e 100644 --- a/1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md +++ b/1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md @@ -1,6 +1,6 @@ # Rest parameters and spread operator -Many JavaScript built-in functions support on arbitrary number of arguments. +Many JavaScript built-in functions support an arbitrary number of arguments. For instance: @@ -35,7 +35,7 @@ For instance, to gather all arguments into array `args`: function sumAll(...args) { // args is the name for the array let sum = 0; - for(let arg of args) sum += arg; + for (let arg of args) sum += arg; return sum; } @@ -207,7 +207,7 @@ alert( [...str] ); // H,e,l,l,o The spread operator internally uses iterators to gather elements, the same way as `for..of` does. -So, for a string, `for..of` returns characters and `...str` becomes `"h","e","l","l","o"`. The list of characters is passed to array initializer `[...str]`. +So, for a string, `for..of` returns characters and `...str` becomes `"H","e","l","l","o"`. The list of characters is passed to array initializer `[...str]`. For this particular task we could also use `Array.from`, because it converts an iterable (like a string) into an array: diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md index 0c718aad..cdb2942b 100644 --- a/1-js/06-advanced-functions/03-closure/article.md +++ b/1-js/06-advanced-functions/03-closure/article.md @@ -296,7 +296,7 @@ let counter2 = makeCounter(); alert( counter1() ); // 0 alert( counter1() ); // 1 -alert( counter2() ); // 0 (independant) +alert( counter2() ); // 0 (independent) ``` @@ -423,7 +423,7 @@ For instance, after `if` finishes, the `alert` below won't see the `user`, hence For a loop, every run has a separate Lexical Environment. If the variable is declared in `for`, then it's also local to that Lexical Environment: ```js run -for(let i = 0; i < 10; i++) { +for (let i = 0; i < 10; i++) { // Each loop has its own Lexical Environment // {i: value} } @@ -567,7 +567,7 @@ Lexical Environment objects that we've been talking about are subjects to same m return function() { alert(value); }; } - // 3 functions in array, every of them links to Lexical Environment + // 3 functions in array, every one of them links to Lexical Environment // from the corresponding f() run // LE LE LE let arr = [f(), f(), f()]; @@ -641,6 +641,6 @@ g(); ```warn header="See ya!" This feature of V8 is good to know. If you are debugging with Chrome/Opera, sooner or later you will meet it. -That is not a bug of debugger, but a special feature of V8. Maybe it will be changed some time. +That is not a bug of debugger, but a special feature of V8. Maybe it will be changed sometime. You always can check for it by running examples on this page. ``` diff --git a/1-js/06-advanced-functions/04-var/article.md b/1-js/06-advanced-functions/04-var/article.md index 9a089b5f..e36d2d2d 100644 --- a/1-js/06-advanced-functions/04-var/article.md +++ b/1-js/06-advanced-functions/04-var/article.md @@ -52,7 +52,7 @@ If we used `let test` on the 2nd line, then it wouldn't be visible to `alert`. B The same thing for loops: `var` cannot be block- or loop-local: ```js -for(var i = 0; i < 10; i++) { +for (var i = 0; i < 10; i++) { // ... } @@ -61,7 +61,7 @@ alert(i); // 10, "i" is visible after loop, it's a global variable */!* ``` -If a code block in inside a function, then `var` becomes a function-level variable: +If a code block is inside a function, then `var` becomes a function-level variable: ```js function sayHi() { @@ -76,7 +76,7 @@ sayHi(); alert(phrase); // Error: phrase is not defined ``` -As we can see, `var` pierces through `if`, `for` or other code blocks. That's because long time ago in JavaScript blocks had no Lexical Environments. And `var` is a reminiscence of that. +As we can see, `var` pierces through `if`, `for` or other code blocks. That's because a long time ago in JavaScript blocks had no Lexical Environments. And `var` is a reminiscence of that. ## "var" are processed at the function start @@ -184,4 +184,4 @@ There are two main differences of `var`: There's one more minor difference related to the global object, we'll cover that in the next chapter. -These differences are actually a bad thing most of time. First, we can't create block-local variables. And hoisting just creates more space for errors. So, for new scripts `var` is used exceptionally rarely. +These differences are actually a bad thing most of the time. First, we can't create block-local variables. And hoisting just creates more space for errors. So, for new scripts `var` is used exceptionally rarely. diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md index 6bd4000a..cc347aae 100644 --- a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md +++ b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md @@ -158,7 +158,7 @@ The `setTimeout` above schedules next call right at the end of the current one ` Recursive `setTimeout` is more flexible method than `setInterval`. This way the next call may be scheduled differently, depending on the results of the current one. -For instance, we need to write a service that each 5 seconds sends a request to server asking for data, but in case the server is overloaded, it should increase the interval to 10, 20, 40 seconds... +For instance, we need to write a service that every 5 seconds sends a request to server asking for data, but in case the server is overloaded, it should increase the interval to 10, 20, 40 seconds... Here's the pseudocode: ```js @@ -178,7 +178,7 @@ let timerId = setTimeout(function request() { ``` -And if we regulary have CPU-hungry tasks, then we can measure the time taken by the execution and plan the next call sooner or later. +And if we regularly have CPU-hungry tasks, then we can measure the time taken by the execution and plan the next call sooner or later. **Recursive `setTimeout` guarantees a delay between the executions, `setInterval` -- does not.** @@ -209,7 +209,7 @@ Did you notice?... **The real delay between `func` calls for `setInterval` is less than in the code!** -That's natural, because the time taken by `func` execution "consumes" a part of the interval. +That's natural, because the time is taken by `func` execution "consumes" a part of the interval. It is possible that `func` execution turns out to be longer than we expected and takes more than 100ms. @@ -235,7 +235,7 @@ setTimeout(function() {...}, 100); For `setInterval` the function stays in memory until `cancelInterval` is called. -There's a side-effect. A function references the outer lexical environment, so, while it lives, outer variables live too. They may take much more memory than the function itself. So when we don't need the scheduled function any more, it's better to cancel it, even if it's very small. +There's a side-effect. A function references the outer lexical environment, so, while it lives, outer variables live too. They may take much more memory than the function itself. So when we don't need the scheduled function anymore, it's better to cancel it, even if it's very small. ```` ## setTimeout(...,0) @@ -260,7 +260,7 @@ The first line "puts the call into calendar after 0ms". But the scheduler will o There's a trick to split CPU-hungry task using `setTimeout`. -For instance, syntax highlighting script (used to colorize code examples on this page) is quite CPU-heavy. To hightlight the code, it performs the analysis, creates many colored elements, adds them to the document -- for a big text that takes a lot. It may even cause the browser to "hang", that's unacceptable. +For instance, syntax highlighting script (used to colorize code examples on this page) is quite CPU-heavy. To highlight the code, it performs the analysis, creates many colored elements, adds them to the document -- for a big text that takes a lot. It may even cause the browser to "hang", that's unacceptable. So we can split the long text to pieces. First 100 lines, then plan another 100 lines using `setTimeout(...,0)`, and so on. @@ -276,7 +276,7 @@ let start = Date.now(); function count() { // do a heavy job - for(let j = 0; j < 1e9; j++) { + for (let j = 0; j < 1e9; j++) { i++; } @@ -401,7 +401,7 @@ Here's the demo: let i = 0; function count() { - for(let j = 0; j < 1e6; j++) { + for (let j = 0; j < 1e6; j++) { i++; // put the current i into the
// (we'll talk more about innerHTML in the specific chapter, should be obvious here) diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/test.js b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/test.js index b9347c90..5adfcb97 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/test.js +++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/test.js @@ -36,9 +36,9 @@ describe("spy", function() { calc.wrappedSum = spy(calc.sum); - assert.equal(calculator.wrappedSum(1, 2), 3); + assert.equal(calc.wrappedSum(1, 2), 3); assert(calc.sum.calledWith(1, 2)); - assert(calc.sum.calledOn(calculator)); + assert(calc.sum.calledOn(calc)); }); }); diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md index e4a30cb8..9ebb7abf 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md @@ -22,7 +22,7 @@ work = spy(work); work(1, 2); // 3 work(4, 5); // 9 -for(let args of work.calls) { +for (let args of work.calls) { alert( 'call:' + args.join() ); // "call:1,2", "call:4,5" } ``` diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/article.md b/1-js/06-advanced-functions/09-call-apply-decorators/article.md index 707bbf58..4065c81a 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/article.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/article.md @@ -135,7 +135,7 @@ func.call(context, arg1, arg2, ...) It runs `func` providing the first argument as `this`, and the next as the arguments. -To put it simple, these two calls do almost the same: +To put it simply, these two calls do almost the same: ```js func(1, 2, 3); func.call(obj, 1, 2, 3) @@ -241,7 +241,7 @@ There are many solutions possible: 1. Implement a new (or use a third-party) map-like data structure that is more versatile and allows multi-keys. 2. Use nested maps: `cache.set(min)` will be a `Map` that stores the pair `(max, result)`. So we can get `result` as `cache.get(min).get(max)`. -3. Join two values into one. In our particular case we can just use a string `"min,max"` as the `Map` key. For flexibility, we can allow to provide a *hashing function* for the decorator, that knows how to make a one value from many. +3. Join two values into one. In our particular case we can just use a string `"min,max"` as the `Map` key. For flexibility, we can allow to provide a *hashing function* for the decorator, that knows how to make one value from many. For many practical applications, the 3rd variant is good enough, so we'll stick to it. @@ -319,7 +319,7 @@ let wrapper = function() { That's called *call forwarding*. The `wrapper` passes everything it gets: the context `this` and arguments to `anotherFunction` and returns back its result. -When an external code calls such `wrapper`, it is undistinguishable from the call of the original function. +When an external code calls such `wrapper`, it is indistinguishable from the call of the original function. Now let's bake it all into the more powerful `cachingDecorator`: @@ -438,7 +438,7 @@ So, technically it takes `this` and joins `this[0]`, `this[1]` ...etc together. *Decorator* is a wrapper around a function that alters its behavior. The main job is still carried out by the function. -It is generally safe to replace a function or a method with a decorated one, except for one little thing. If the original function had properties on it, like `func.calledCount` or whatever, then the decorated one will not provide them. Because that is a wrapper. So one need to be careful if one uses them. Some decorators provide their own properties. +It is generally safe to replace a function or a method with a decorated one, except for one little thing. If the original function had properties on it, like `func.calledCount` or whatever, then the decorated one will not provide them. Because that is a wrapper. So one needs to be careful if one uses them. Some decorators provide their own properties. Decorators can be seen as "features" or "aspects" that can be added to a function. We can add one or add many. And all this without changing its code! diff --git a/1-js/06-advanced-functions/12-arrow-functions/article.md b/1-js/06-advanced-functions/12-arrow-functions/article.md index dcae22a4..92a88426 100644 --- a/1-js/06-advanced-functions/12-arrow-functions/article.md +++ b/1-js/06-advanced-functions/12-arrow-functions/article.md @@ -125,4 +125,4 @@ Arrow functions: - Can't be called with `new`. - (They also don't have `super`, but we didn't study it. Will be in the chapter ). -That's because they are meant for short pieces of code that does not have their own "context", but rather works in the current one. And they really shine in that use case. +That's because they are meant for short pieces of code that do not have their own "context", but rather works in the current one. And they really shine in that use case. diff --git a/1-js/07-object-oriented-programming/01-property-descriptors/article.md b/1-js/07-object-oriented-programming/01-property-descriptors/article.md index e927d5d7..5eadd6f4 100644 --- a/1-js/07-object-oriented-programming/01-property-descriptors/article.md +++ b/1-js/07-object-oriented-programming/01-property-descriptors/article.md @@ -15,7 +15,7 @@ Object properties, besides a **`value`**, have three special attributes (so-call - **`enumerable`** -- if `true`, then listed in loops, otherwise not listed. - **`configurable`** -- if `true`, the property can be deleted and these attributes can be modified, otherwise not. -We didn't see them yet, because generally they do not show up. When we create a property "the usual way", all of them are `true`. But we also can change them any time. +We didn't see them yet, because generally they do not show up. When we create a property "the usual way", all of them are `true`. But we also can change them anytime. First, let's see how to get those flags. @@ -156,7 +156,7 @@ let user = { }; // By default, both our properties are listed: -for(let key in user) alert(key); // name, toString +for (let key in user) alert(key); // name, toString ``` If we don't like it, then we can set `enumerable:false`. Then it won't appear in `for..in` loop, just like the built-in one: @@ -178,7 +178,7 @@ Object.defineProperty(user, "toString", { *!* // Now our toString disappears: */!* -for(let key in user) alert(key); // name +for (let key in user) alert(key); // name ``` Non-enumerable properties are also excluded from `Object.keys`: @@ -282,7 +282,7 @@ let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj)); Normally when we clone an object, we use an assignment to copy properties, like this: ```js -for(let key in user) { +for (let key in user) { clone[key] = user[key] } ``` 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 0825b752..5fce2c4b 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 @@ -55,7 +55,7 @@ let scrollHeight = Math.max( document.body.clientHeight, document.documentElement.clientHeight ); -alert('Full document width, with scrolled out part: ' + scrollHeight); +alert('Full document height, with scrolled out part: ' + scrollHeight); ``` Why so? Better don't ask. These inconsistencies come from ancient times, not a "smart" logic. diff --git a/2-ui/3-event-details/8-onscroll/1-endless-page/solution.md b/2-ui/3-event-details/8-onscroll/1-endless-page/solution.md index a3f21b57..f7412bd4 100644 --- a/2-ui/3-event-details/8-onscroll/1-endless-page/solution.md +++ b/2-ui/3-event-details/8-onscroll/1-endless-page/solution.md @@ -18,7 +18,7 @@ For instance, if the height of the whole HTML document is 2000px, then: document.documentElement.getBoundingClientRect().top = 0 // window-relative bottom = 2000 -// the document is long, so that is probably far beyound the window bottom +// the document is long, so that is probably far beyond the window bottom document.documentElement.getBoundingClientRect().bottom = 2000 ``` diff --git a/2-ui/3-event-details/8-onscroll/1-endless-page/task.md b/2-ui/3-event-details/8-onscroll/1-endless-page/task.md index 4b49070b..7c8d14fc 100644 --- a/2-ui/3-event-details/8-onscroll/1-endless-page/task.md +++ b/2-ui/3-event-details/8-onscroll/1-endless-page/task.md @@ -12,7 +12,7 @@ Like this: Please note two important features of the scroll: -1. **The scroll is "elastic".** We can scroll a little beyound the document start or end in some browsers/devices (empty space below is shown, and then the document will automatically "bounces back" to normal). +1. **The scroll is "elastic".** We can scroll a little beyond the document start or end in some browsers/devices (empty space below is shown, and then the document will automatically "bounces back" to normal). 2. **The scroll is imprecise.** When we scroll to page end, then we may be in fact like 0-50px away from the real document bottom. So, "scrolling to the end" should mean that the visitor is no more than 100px away from the document end. diff --git a/2-ui/4-forms-controls/2-focus-blur/article.md b/2-ui/4-forms-controls/2-focus-blur/article.md index 45b539a6..09478a29 100644 --- a/2-ui/4-forms-controls/2-focus-blur/article.md +++ b/2-ui/4-forms-controls/2-focus-blur/article.md @@ -4,9 +4,9 @@ An element receives a focus when the user either clicks on it or uses the `key:T Focusing generally means: "prepare to accept the data here", so that's the moment when we can run the code to initialize or load something. -The moment of loosing the focus ("blur") can be even more important. That's when a user clicks somewhere else or presses `key:Tab` to go to the next form field, or there are other means as well. +The moment of losing the focus ("blur") can be even more important. That's when a user clicks somewhere else or presses `key:Tab` to go to the next form field, or there are other means as well. -Loosing the focus generally means: "the data has been entered", so we can run the code to check it or even to save it to the server and so on. +Losing the focus generally means: "the data has been entered", so we can run the code to check it or even to save it to the server and so on. There are important peculiarities when working with focus events. We'll do the best to cover them here. @@ -14,7 +14,7 @@ There are important peculiarities when working with focus events. We'll do the b ## Events focus/blur -The `focus` event is called on focusing, and `blur` -- when the element looses the focus. +The `focus` event is called on focusing, and `blur` -- when the element loses the focus. Let's use them for validation of an input field. @@ -90,7 +90,7 @@ It works in all browsers except Firefox ([bug](https://bugzilla.mozilla.org/show If we enter something into the input and then try to use `key:Tab` or click away from the ``, then `onblur` returns the focus back. -Please note that we can't "prevent loosing focus" by calling `event.preventDefault()` in `onblur`, because `onblur` works *after* the element lost the focus. +Please note that we can't "prevent losing focus" by calling `event.preventDefault()` in `onblur`, because `onblur` works *after* the element lost the focus. ```warn header="JavaScript-initiated focus loss" A focus loss can occur for many reasons. @@ -214,7 +214,7 @@ So here's another working variant: ## Summary -Events `focus` and `blur` trigger on focusing/loosing focus on the element. +Events `focus` and `blur` trigger on focusing/losing focus on the element. Their specials are: - They do not bubble. Can use capturing state instead or `focusin/focusout`. diff --git a/4-frames-and-windows/03-cross-window-communication/article.md b/4-frames-and-windows/03-cross-window-communication/article.md index 15394969..e134fcda 100644 --- a/4-frames-and-windows/03-cross-window-communication/article.md +++ b/4-frames-and-windows/03-cross-window-communication/article.md @@ -27,7 +27,7 @@ If we have a reference to another window (a popup or iframe), and that window co If it comes from another origin, then we can only change its location. Please note: not *read* the location, but *modify* it, redirect it to another place. That's safe, because the URL may contain sensitive parameters, so reading it from another origin is prohibited, but changing is not. -Also such windows windows may exchange messages. Soon about that later. +Also such windows may exchange messages. Soon about that later. ````warn header="Exclusion: subdomains may be same-origin" diff --git a/5-regular-expressions/02-regexp-methods/article.md b/5-regular-expressions/02-regexp-methods/article.md index 1d808bf3..362a4d79 100644 --- a/5-regular-expressions/02-regexp-methods/article.md +++ b/5-regular-expressions/02-regexp-methods/article.md @@ -153,7 +153,7 @@ We can use special characters in it: |`$&`|the whole match| |$`|a part of the string before the match| |`$'`|a part of the string after the match| -|`$n`|if `n` is a 1-2 digit number, then it means the contents of n-th parentheses counting fro left to right| +|`$n`|if `n` is a 1-2 digit number, then it means the contents of n-th parentheses counting from left to right| For instance let's use `$&` to replace all entries of `"John"` by `"Mr.John"`: diff --git a/5-regular-expressions/03-regexp-character-classes/article.md b/5-regular-expressions/03-regexp-character-classes/article.md index 41372bd0..a31658ec 100644 --- a/5-regular-expressions/03-regexp-character-classes/article.md +++ b/5-regular-expressions/03-regexp-character-classes/article.md @@ -101,9 +101,9 @@ So it matches `pattern:\bHello\b` and `pattern:\bJava\b`, but not `pattern:\bHel ```js run alert( "Hello, Java!".match(/\bHello\b/) ); // Hello -alert( "Hello, Java!".match(/\Java\b/) ); // Java -alert( "Hello, Java!".match(/\Hell\b/) ); // null -alert( "Hello, Java!".match(/\Java!\b/) ); // null +alert( "Hello, Java!".match(/\bJava\b/) ); // Java +alert( "Hello, Java!".match(/\bHell\b/) ); // null +alert( "Hello, Java!".match(/\bJava!\b/) ); // null ``` Once again let's note that `pattern:\b` makes the searching engine to test for the boundary, so that `pattern:Java\b` finds `match:Java` only when followed by a word boundary, but it does not add a letter to the result. diff --git a/5-regular-expressions/04-regexp-escaping/article.md b/5-regular-expressions/04-regexp-escaping/article.md index cb7a3eb1..11767c3d 100644 --- a/5-regular-expressions/04-regexp-escaping/article.md +++ b/5-regular-expressions/04-regexp-escaping/article.md @@ -30,7 +30,7 @@ alert( "function g()".match(/g\(\)/) ); // "g()" If we're looking for a backslash `\`, then we should double it: ```js run -alert( "1\2".match(/\\/) ); // '\' +alert( "1\\2".match(/\\/) ); // '\' ``` ## A slash diff --git a/6-async/03-promise-chaining/article.md b/6-async/03-promise-chaining/article.md index d841fd6b..5d08530e 100644 --- a/6-async/03-promise-chaining/article.md +++ b/6-async/03-promise-chaining/article.md @@ -365,7 +365,7 @@ loadJson('/article/promise-chaining/user.json') ## Error handling -Asynchronous actions may sometimes fail: in case of an error the corresponding promises becomes rejected. For instance, `fetch` fails if the remote server is not available. We can use `.catch` to handle errors (rejections). +Asynchronous actions may sometimes fail: in case of an error the corresponding promise becomes rejected. For instance, `fetch` fails if the remote server is not available. We can use `.catch` to handle errors (rejections). Promise chaining is great at that aspect. When a promise rejects, the control jumps to the closest rejection handler down the chain. That's very convenient in practice.