diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md
index 251a347e9e..d4c81a3e3a 100644
--- a/1-js/01-getting-started/1-intro/article.md
+++ b/1-js/01-getting-started/1-intro/article.md
@@ -68,7 +68,7 @@ Examples of such restrictions include:
Modern browsers allow it to work with files, but the access is limited and only provided if the user does certain actions, like "dropping" a file into a browser window or selecting it via an `` tag.
There are ways to interact with camera/microphone and other devices, but they require a user's explicit permission. So a JavaScript-enabled page may not sneakily enable a web-camera, observe the surroundings and send the information to the [NSA](https://en.wikipedia.org/wiki/National_Security_Agency).
-- Different tabs/windows generally do not know about each other. Sometimes they do; for example when one window uses JavaScript to open the other one. But even in this case, JavaScript from one page may not access the other if they come from different sites (from a different domain, protocol or port).
+- Different tabs/windows generally do not know about each other. Sometimes they do, for example when one window uses JavaScript to open the other one. But even in this case, JavaScript from one page may not access the other if they come from different sites (from a different domain, protocol or port).
This is called the "Same Origin Policy". To work around that, *both pages* must agree for data exchange and contain a special JavaScript code that handles it. We'll cover that in the tutorial.
diff --git a/1-js/01-getting-started/4-devtools/article.md b/1-js/01-getting-started/4-devtools/article.md
index 50926d4f76..08aeaf9875 100644
--- a/1-js/01-getting-started/4-devtools/article.md
+++ b/1-js/01-getting-started/4-devtools/article.md
@@ -8,7 +8,7 @@ To see errors and get a lot of other useful information about scripts, "develope
Most developers lean towards Chrome or Firefox for development because those browsers have the best developer tools. Other browsers also provide developer tools, sometimes with special features, but are usually playing "catch-up" to Chrome or Firefox. So most developers have a "favorite" browser and switch to others if a problem is browser-specific.
-Developer tools are potent; they have many features. To start, we'll learn how to open them, look at errors, and run JavaScript commands.
+Developer tools are potent, they have many features. To start, we'll learn how to open them, look at errors, and run JavaScript commands.
## Google Chrome
diff --git a/1-js/03-code-quality/02-coding-style/article.md b/1-js/03-code-quality/02-coding-style/article.md
index 4cdb23808b..d9a0b3be7a 100644
--- a/1-js/03-code-quality/02-coding-style/article.md
+++ b/1-js/03-code-quality/02-coding-style/article.md
@@ -328,7 +328,7 @@ Here's an example of an `.eslintrc` file:
},
"rules": {
"no-console": 0,
- "indent": ["warning", 2]
+ "indent": 2
}
}
```
diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md
index 75db49d2f7..24091eb438 100644
--- a/1-js/03-code-quality/06-polyfills/article.md
+++ b/1-js/03-code-quality/06-polyfills/article.md
@@ -23,7 +23,7 @@ Actually, there are two parts in Babel:
2. Second, the polyfill.
- New language features may include new built-in functions and syntax constructs.
+ New language features may include not only syntax constructs, but also built-in functions.
The transpiler rewrites the code, transforming syntax constructs into older ones. But as for new built-in functions, we need to implement them. JavaScript is a highly dynamic language, scripts may add/modify any functions, so that they behave according to the modern standard.
A script that updates/adds new functions is called "polyfill". It "fills in" the gap and adds missing implementations.
diff --git a/1-js/04-object-basics/03-garbage-collection/article.md b/1-js/04-object-basics/03-garbage-collection/article.md
index e20e5a5d88..9750d33a20 100644
--- a/1-js/04-object-basics/03-garbage-collection/article.md
+++ b/1-js/04-object-basics/03-garbage-collection/article.md
@@ -23,7 +23,7 @@ Simply put, "reachable" values are those that are accessible or usable somehow.
2. Any other value is considered reachable if it's reachable from a root by a reference or by a chain of references.
- For instance, if there's an object in a global variable, and that object has a property referencing another object, that object is considered reachable. And those that it references are also reachable. Detailed examples to follow.
+ For instance, if there's an object in a global variable, and that object has a property referencing another object, *that* object is considered reachable. And those that it references are also reachable. Detailed examples to follow.
There's a background process in the JavaScript engine that is called [garbage collector](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)). It monitors all objects and removes those that have become unreachable.
diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md
index c4a0421300..97fab12ebb 100644
--- a/1-js/04-object-basics/07-optional-chaining/article.md
+++ b/1-js/04-object-basics/07-optional-chaining/article.md
@@ -9,44 +9,80 @@ The optional chaining `?.` is a safe way to access nested object properties, eve
If you've just started to read the tutorial and learn JavaScript, maybe the problem hasn't touched you yet, but it's quite common.
-As an example, let's consider objects for user data. Most of our users have addresses in `user.address` property, with the street `user.address.street`, but some did not provide them.
+As an example, let's say we have `user` objects that hold the information about our users.
-In such case, when we attempt to get `user.address.street`, we'll get an error:
+Most of our users have addresses in `user.address` property, with the street `user.address.street`, but some did not provide them.
+
+In such case, when we attempt to get `user.address.street`, and the user happens to be without an address, we get an error:
```js run
-let user = {}; // the user without "address" property
+let user = {}; // a user without "address" property
alert(user.address.street); // Error!
```
-That's the expected result, JavaScript works like this, but many practical cases we'd prefer to get `undefined` instead of an error (meaning "no street").
+That's the expected result. JavaScript works like this. As `user.address` is `undefined`, an attempt to get `user.address.street` fails with an error.
+
+In many practical cases we'd prefer to get `undefined` instead of an error here (meaning "no street").
-...And another example. In the web development, we may need to get an information about an element on the page, that sometimes doesn't exist:
+...And another example. In the web development, we can get an object that corresponds to a web page element using a special method call, such as `document.querySelector('.elem')`, and it returns `null` when there's no such element.
```js run
-// Error if the result of querySelector(...) is null
-let html = document.querySelector('.my-element').innerHTML;
+// document.querySelector('.elem') is null if there's no element
+let html = document.querySelector('.elem').innerHTML; // error if it's null
```
-Before `?.` appeared in the language, the `&&` operator was used to work around that.
+Once again, if the element doesn't exist, we'll get an error accessing `.innerHTML` of `null`. And in some cases, when the absence of the element is normal, we'd like to avoid the error and just accept `html = null` as the result.
-For example:
+How can we do this?
+
+The obvious solution would be to check the value using `if` or the conditional operator `?`, before accessing its property, like this:
+
+```js
+let user = {};
+
+alert(user.address ? user.address.street : undefined);
+```
+
+It works, there's no error... But it's quite inelegant. As you can see, the `"user.address"` appears twice in the code. For more deeply nested properties, that becomes a problem as more repetitions are required.
+
+E.g. let's try getting `user.address.street.name`.
+
+We need to check both `user.address` and `user.address.street`:
+
+```js
+let user = {}; // user has no address
+
+alert(user.address ? user.address.street ? user.address.street.name : null : null);
+```
+
+That's just awful, one may even have problems understanding such code.
+
+Don't even care to, as there's a better way to write it, using the `&&` operator:
```js run
let user = {}; // user has no address
-alert( user && user.address && user.address.street ); // undefined (no error)
+alert( user.address && user.address.street && user.address.street.name ); // undefined (no error)
```
-AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but is cumbersome to write.
+AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but also isn't ideal.
+
+As you can see, property names are still duplicated in the code. E.g. in the code above, `user.address` appears three times.
+
+That's why the optional chaining `?.` was added to the language. To solve this problem once and for all!
## Optional chaining
-The optional chaining `?.` stops the evaluation and returns `undefined` if the part before `?.` is `undefined` or `null`.
+The optional chaining `?.` stops the evaluation if the part before `?.` is `undefined` or `null` and returns that part.
**Further in this article, for brevity, we'll be saying that something "exists" if it's not `null` and not `undefined`.**
-Here's the safe way to access `user.address.street`:
+In other words, `value?.prop`:
+- is the same as `value.prop` if `value` exists,
+- otherwise (when `value` is `undefined/null`) it returns `undefined`.
+
+Here's the safe way to access `user.address.street` using `?.`:
```js run
let user = {}; // user has no address
@@ -54,6 +90,8 @@ let user = {}; // user has no address
alert( user?.address?.street ); // undefined (no error)
```
+The code is short and clean, there's no duplication at all.
+
Reading the address with `user?.address` works even if `user` object doesn't exist:
```js run
@@ -65,14 +103,12 @@ alert( user?.address.street ); // undefined
Please note: the `?.` syntax makes optional the value before it, but not any further.
-In the example above, `user?.` allows only `user` to be `null/undefined`.
-
-On the other hand, if `user` does exist, then it must have `user.address` property, otherwise `user?.address.street` gives an error at the second dot.
+E.g. in `user?.address.street.name` the `?.` allows `user` to be `null/undefined`, but it's all it does. Further properties are accessed in a regular way. If we want some of them to be optional, then we'll need to replace more `.` with `?.`.
```warn header="Don't overuse the optional chaining"
We should use `?.` only where it's ok that something doesn't exist.
-For example, if according to our coding logic `user` object must be there, but `address` is optional, then `user.address?.street` would be better.
+For example, if according to our coding logic `user` object must exist, but `address` is optional, then we should write `user.address?.street`, but not `user?.address?.street`.
So, if `user` happens to be undefined due to a mistake, we'll see a programming error about it and fix it. Otherwise, coding errors can be silenced where not appropriate, and become more difficult to debug.
```
@@ -84,7 +120,7 @@ If there's no variable `user` at all, then `user?.anything` triggers an error:
// ReferenceError: user is not defined
user?.address;
```
-There must be a declaration (e.g. `let/const/var user`). The optional chaining works only for declared variables.
+The variable must be declared (e.g. `let/const/var user` or as a function parameter). The optional chaining works only for declared variables.
````
## Short-circuiting
@@ -113,17 +149,20 @@ For example, `?.()` is used to call a function that may not exist.
In the code below, some of our users have `admin` method, and some don't:
```js run
-let user1 = {
+let userAdmin = {
admin() {
alert("I am admin");
}
-}
+};
-let user2 = {};
+let userGuest = {};
+
+*!*
+userAdmin.admin?.(); // I am admin
+*/!*
*!*
-user1.admin?.(); // I am admin
-user2.admin?.();
+userGuest.admin?.(); // nothing (no such method)
*/!*
```
diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md
index e768f4d473..7f48a40643 100644
--- a/1-js/05-data-types/02-number/article.md
+++ b/1-js/05-data-types/02-number/article.md
@@ -406,7 +406,7 @@ A few examples:
alert( Math.pow(2, 10) ); // 2 in power 10 = 1024
```
-There are more functions and constants in `Math` object, including trigonometry, which you can find in the [docs for the Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) object.
+There are more functions and constants in `Math` object, including trigonometry, which you can find in the [docs for the Math object](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math).
## Summary
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 ace4c7887f..bab880a27c 100644
--- a/1-js/05-data-types/05-array-methods/article.md
+++ b/1-js/05-data-types/05-array-methods/article.md
@@ -743,7 +743,7 @@ These methods are the most used ones, they cover 99% of use cases. But there are
The function `fn` is called on each element of the array similar to `map`. If any/all results are `true`, returns `true`, otherwise `false`.
- These methods behave sort of like `||` and `&&` operators: if `fn` returns a truthy value, `arr.some()` immediately returns `true` and stops iterating over the rest items; if `fn` returns a falsy value, `arr.every()` immediately returns `false` and stops iterating over the rest items as well.
+ These methods behave sort of like `||` and `&&` operators: if `fn` returns a truthy value, `arr.some()` immediately returns `true` and stops iterating over the rest items; if `fn` returns a falsy value, `arr.every()` immediately returns `false` and stops iterating over the rest items as well.
We can use `every` to compare arrays:
```js run
diff --git a/1-js/05-data-types/08-weakmap-weakset/article.md b/1-js/05-data-types/08-weakmap-weakset/article.md
index bcc5e5e6f5..178a4e2332 100644
--- a/1-js/05-data-types/08-weakmap-weakset/article.md
+++ b/1-js/05-data-types/08-weakmap-weakset/article.md
@@ -30,7 +30,8 @@ let array = [ john ];
john = null; // overwrite the reference
*!*
-// john is stored inside the array, so it won't be garbage-collected
+// the object previously referenced by john is stored inside the array
+// therefore it won't be garbage-collected
// we can get it as array[0]
*/!*
```
diff --git a/1-js/06-advanced-functions/01-recursion/02-factorial/solution.md b/1-js/06-advanced-functions/01-recursion/02-factorial/solution.md
index 59040a2b7a..09e511db5c 100644
--- a/1-js/06-advanced-functions/01-recursion/02-factorial/solution.md
+++ b/1-js/06-advanced-functions/01-recursion/02-factorial/solution.md
@@ -1,4 +1,4 @@
-By definition, a factorial is `n!` can be written as `n * (n-1)!`.
+By definition, a factorial `n!` can be written as `n * (n-1)!`.
In other words, the result of `factorial(n)` can be calculated as `n` multiplied by the result of `factorial(n-1)`. And the call for `n-1` can recursively descend lower, and lower, till `1`.
diff --git a/1-js/06-advanced-functions/01-recursion/article.md b/1-js/06-advanced-functions/01-recursion/article.md
index 320de62f05..17fe5ea3e6 100644
--- a/1-js/06-advanced-functions/01-recursion/article.md
+++ b/1-js/06-advanced-functions/01-recursion/article.md
@@ -132,7 +132,7 @@ We can sketch it as:
-That's when the function starts to execute. The condition `n == 1` is false, so the flow continues into the second branch of `if`:
+That's when the function starts to execute. The condition `n == 1` is falsy, so the flow continues into the second branch of `if`:
```js run
function pow(x, n) {
@@ -188,7 +188,7 @@ The new current execution context is on top (and bold), and previous remembered
When we finish the subcall -- it is easy to resume the previous context, because it keeps both variables and the exact place of the code where it stopped.
```smart
-Here in the picture we use the word "line", as our example there's only one subcall in line, but generally a single line of code may contain multiple subcalls, like `pow(…) + pow(…) + somethingElse(…)`.
+Here in the picture we use the word "line", as in our example there's only one subcall in line, but generally a single line of code may contain multiple subcalls, like `pow(…) + pow(…) + somethingElse(…)`.
So it would be more precise to say that the execution resumes "immediately after the subcall".
```
diff --git a/1-js/06-advanced-functions/04-var/article.md b/1-js/06-advanced-functions/04-var/article.md
index b2559989bd..205c0a18d2 100644
--- a/1-js/06-advanced-functions/04-var/article.md
+++ b/1-js/06-advanced-functions/04-var/article.md
@@ -82,7 +82,7 @@ function sayHi() {
}
sayHi();
-alert(phrase); // Error: phrase is not defined (Check the Developer Console)
+alert(phrase); // Error: phrase is not defined
```
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 remnant of that.
@@ -279,7 +279,7 @@ In all the above cases we declare a Function Expression and run it immediately.
There are two main differences of `var` compared to `let/const`:
-1. `var` variables have no block scope; their visibility is scoped to current function, or global, if declared outside function.
+1. `var` variables have no block scope, their visibility is scoped to current function, or global, if declared outside function.
2. `var` declarations are processed at function start (script start for globals).
There's one more very minor difference related to the global object, that we'll cover in the next chapter.
diff --git a/1-js/06-advanced-functions/05-global-object/article.md b/1-js/06-advanced-functions/05-global-object/article.md
index 679db05c17..ae4883c488 100644
--- a/1-js/06-advanced-functions/05-global-object/article.md
+++ b/1-js/06-advanced-functions/05-global-object/article.md
@@ -5,7 +5,7 @@ The global object provides variables and functions that are available anywhere.
In a browser it is named `window`, for Node.js it is `global`, for other environments it may have another name.
-Recently, `globalThis` was added to the language, as a standardized name for a global object, that should be supported across all environments. It's supported in all major browsers.
+Recently, `globalThis` was added to the language, as a standardized name for a global object, that should be supported across all environments. It's supported in all major browsers.
We'll use `window` here, assuming that our environment is a browser. If your script may run in other environments, it's better to use `globalThis` instead.
@@ -25,6 +25,8 @@ var gVar = 5;
alert(window.gVar); // 5 (became a property of the global object)
```
+The same effect have function declarations (statements with `function` keyword in the main code flow, not function expressions).
+
Please don't rely on that! This behavior exists for compatibility reasons. Modern scripts use [JavaScript modules](info:modules) where such thing doesn't happen.
If we used `let` instead, such thing wouldn't happen:
diff --git a/1-js/06-advanced-functions/06-function-object/article.md b/1-js/06-advanced-functions/06-function-object/article.md
index ed848c0c59..e930902902 100644
--- a/1-js/06-advanced-functions/06-function-object/article.md
+++ b/1-js/06-advanced-functions/06-function-object/article.md
@@ -347,7 +347,7 @@ If the function is declared as a Function Expression (not in the main code flow)
Also, functions may carry additional properties. Many well-known JavaScript libraries make great use of this feature.
-They create a "main" function and attach many other "helper" functions to it. For instance, the [jQuery](https://jquery.com) library creates a function named `$`. The [lodash](https://lodash.com) library creates a function `_`, and then adds `_.clone`, `_.keyBy` and other properties to it (see the [docs](https://lodash.com/docs) when you want learn more about them). Actually, they do it to lessen their pollution of the global space, so that a single library gives only one global variable. That reduces the possibility of naming conflicts.
+They create a "main" function and attach many other "helper" functions to it. For instance, the [jQuery](https://jquery.com) library creates a function named `$`. The [lodash](https://lodash.com) library creates a function `_`, and then adds `_.clone`, `_.keyBy` and other properties to it (see the [docs](https://lodash.com/docs) when you want to learn more about them). Actually, they do it to lessen their pollution of the global space, so that a single library gives only one global variable. That reduces the possibility of naming conflicts.
So, a function can do a useful job by itself and also carry a bunch of other functionality in properties.
diff --git a/1-js/06-advanced-functions/07-new-function/article.md b/1-js/06-advanced-functions/07-new-function/article.md
index 3214ba3769..ffe264a4e7 100644
--- a/1-js/06-advanced-functions/07-new-function/article.md
+++ b/1-js/06-advanced-functions/07-new-function/article.md
@@ -92,7 +92,7 @@ What if it could access the outer variables?
The problem is that before JavaScript is published to production, it's compressed using a *minifier* -- a special program that shrinks code by removing extra comments, spaces and -- what's important, renames local variables into shorter ones.
-For instance, if a function has `let userName`, minifier replaces it `let a` (or another letter if this one is occupied), and does it everywhere. That's usually a safe thing to do, because the variable is local, nothing outside the function can access it. And inside the function, minifier replaces every mention of it. Minifiers are smart, they analyze the code structure, so they don't break anything. They're not just a dumb find-and-replace.
+For instance, if a function has `let userName`, minifier replaces it with `let a` (or another letter if this one is occupied), and does it everywhere. That's usually a safe thing to do, because the variable is local, nothing outside the function can access it. And inside the function, minifier replaces every mention of it. Minifiers are smart, they analyze the code structure, so they don't break anything. They're not just a dumb find-and-replace.
So if `new Function` had access to outer variables, it would be unable to find renamed `userName`.
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 95fddea652..9841026879 100644
--- a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md
+++ b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md
@@ -129,7 +129,7 @@ setTimeout(() => { clearInterval(timerId); alert('stop'); }, 5000);
```smart header="Time goes on while `alert` is shown"
In most browsers, including Chrome and Firefox the internal timer continues "ticking" while showing `alert/confirm/prompt`.
-So if you run the code above and don't dismiss the `alert` window for some time, then in the next `alert` will be shown immediately as you do it. The actual interval between alerts will be shorter than 2 seconds.
+So if you run the code above and don't dismiss the `alert` window for some time, then the next `alert` will be shown immediately as you do it. The actual interval between alerts will be shorter than 2 seconds.
```
## Nested setTimeout
@@ -281,7 +281,7 @@ The similar thing happens if we use `setInterval` instead of `setTimeout`: `setI
That limitation comes from ancient times and many scripts rely on it, so it exists for historical reasons.
-For server-side JavaScript, that limitation does not exist, and there exist other ways to schedule an immediate asynchronous job, like [setImmediate](https://nodejs.org/api/timers.html) for Node.js. So this note is browser-specific.
+For server-side JavaScript, that limitation does not exist, and there exist other ways to schedule an immediate asynchronous job, like [setImmediate](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args) for Node.js. So this note is browser-specific.
````
## Summary
@@ -290,7 +290,7 @@ For server-side JavaScript, that limitation does not exist, and there exist othe
- To cancel the execution, we should call `clearTimeout/clearInterval` with the value returned by `setTimeout/setInterval`.
- Nested `setTimeout` calls are a more flexible alternative to `setInterval`, allowing us to set the time *between* executions more precisely.
- Zero delay scheduling with `setTimeout(func, 0)` (the same as `setTimeout(func)`) is used to schedule the call "as soon as possible, but after the current script is complete".
-- The browser limits the minimal delay for five or more nested call of `setTimeout` or for `setInterval` (after 5th call) to 4ms. That's for historical reasons.
+- The browser limits the minimal delay for five or more nested calls of `setTimeout` or for `setInterval` (after 5th call) to 4ms. That's for historical reasons.
Please note that all scheduling methods do not *guarantee* the exact delay.
diff --git a/1-js/08-prototypes/01-prototype-inheritance/article.md b/1-js/08-prototypes/01-prototype-inheritance/article.md
index e57808051d..cd4b94d327 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/article.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/article.md
@@ -12,7 +12,7 @@ In JavaScript, objects have a special hidden property `[[Prototype]]` (as named

-The prototype is a little bit "magical". When we want to read a property from `object`, and it's missing, JavaScript automatically takes it from the prototype. In programming, such thing is called "prototypal inheritance". Many cool language features and programming techniques are based on it.
+When we read a property from `object`, and it's missing, JavaScript automatically takes it from the prototype. In programming, such thing is called "prototypal inheritance". And soon we'll study many examples of such inheritance, as well as cooler language features built upon it.
The property `[[Prototype]]` is internal and hidden, but there are many ways to set it.
@@ -27,19 +27,11 @@ let rabbit = {
};
*!*
-rabbit.__proto__ = animal;
+rabbit.__proto__ = animal; // sets rabbit.[[Prototype]] = animal
*/!*
```
-```smart header="`__proto__` is a historical getter/setter for `[[Prototype]]`"
-Please note that `__proto__` is *not the same* as `[[Prototype]]`. It's a getter/setter for it.
-
-It exists for historical reasons. In modern language it is replaced with functions `Object.getPrototypeOf/Object.setPrototypeOf` that also get/set the prototype. We'll study the reasons for that and these functions later.
-
-By the specification, `__proto__` must only be supported by browsers, but in fact all environments including server-side support it. For now, as `__proto__` notation is a little bit more intuitively obvious, we'll use it in the examples.
-```
-
-If we look for a property in `rabbit`, and it's missing, JavaScript automatically takes it from `animal`.
+Now if we read a property from `rabbit`, and it's missing, JavaScript will automatically take it from `animal`.
For instance:
@@ -130,6 +122,8 @@ alert(longEar.jumps); // true (from rabbit)

+Now if we read something from `longEar`, and it's missing, JavaScript will look for it in `rabbit`, and then in `animal`.
+
There are only two limitations:
1. The references can't go in circles. JavaScript will throw an error if we try to assign `__proto__` in a circle.
@@ -137,6 +131,19 @@ There are only two limitations:
Also it may be obvious, but still: there can be only one `[[Prototype]]`. An object may not inherit from two others.
+
+```smart header="`__proto__` is a historical getter/setter for `[[Prototype]]`"
+It's a common mistake of novice developers not to know the difference between these two.
+
+Please note that `__proto__` is *not the same* as the internal `[[Prototype]]` property. It's a getter/setter for `[[Prototype]]`. Later we'll see situations where it matters, for now let's just keep it in mind, as we build our understanding of JavaScript language.
+
+The `__proto__` property is a bit outdated. It exists for historical reasons, modern JavaScript suggests that we should use `Object.getPrototypeOf/Object.setPrototypeOf` functions instead that get/set the prototype. We'll also cover these functions later.
+
+By the specification, `__proto__` must only be supported by browsers. In fact though, all environments including server-side support `__proto__`, so we're quite safe using it.
+
+As the `__proto__` notation is a bit more intuitively obvious, we use it in the examples.
+```
+
## Writing doesn't use prototype
The prototype is only used for reading properties.
@@ -198,8 +205,8 @@ alert(admin.fullName); // John Smith (*)
// setter triggers!
admin.fullName = "Alice Cooper"; // (**)
-alert(admin.fullName); // Alice Cooper , state of admin modified
-alert(user.fullName); // John Smith , state of user protected
+alert(admin.fullName); // Alice Cooper, state of admin modified
+alert(user.fullName); // John Smith, state of user protected
```
Here in the line `(*)` the property `admin.fullName` has a getter in the prototype `user`, so it is called. And in the line `(**)` the property has a setter in the prototype, so it is called.
diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md
index e460ef016c..a4ce2646ca 100644
--- a/1-js/08-prototypes/04-prototype-methods/article.md
+++ b/1-js/08-prototypes/04-prototype-methods/article.md
@@ -176,8 +176,8 @@ alert(Object.keys(chineseDictionary)); // hello,bye
Modern methods to set up and directly access the prototype are:
- [Object.create(proto, [descriptors])](mdn:js/Object/create) -- creates an empty object with a given `proto` as `[[Prototype]]` (can be `null`) and optional property descriptors.
-- [Object.getPrototypeOf(obj)](mdn:js/Object.getPrototypeOf) -- returns the `[[Prototype]]` of `obj` (same as `__proto__` getter).
-- [Object.setPrototypeOf(obj, proto)](mdn:js/Object.setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto` (same as `__proto__` setter).
+- [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returns the `[[Prototype]]` of `obj` (same as `__proto__` getter).
+- [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto` (same as `__proto__` setter).
The built-in `__proto__` getter/setter is unsafe if we'd want to put user-generated keys into an object. Just because a user may enter `"__proto__"` as the key, and there'll be an error, with hopefully light, but generally unpredictable consequences.
diff --git a/1-js/09-classes/01-class/1-rewrite-to-class/task.md b/1-js/09-classes/01-class/1-rewrite-to-class/task.md
index 05365e4104..4477de6799 100644
--- a/1-js/09-classes/01-class/1-rewrite-to-class/task.md
+++ b/1-js/09-classes/01-class/1-rewrite-to-class/task.md
@@ -4,6 +4,6 @@ importance: 5
# Rewrite to class
-The `Clock` class is written in functional style. Rewrite it the "class" syntax.
+The `Clock` class (see the sandbox) is written in functional style. Rewrite it in the "class" syntax.
P.S. The clock ticks in the console, open it to see.
diff --git a/1-js/09-classes/01-class/article.md b/1-js/09-classes/01-class/article.md
index 49a891b71c..13686acdf4 100644
--- a/1-js/09-classes/01-class/article.md
+++ b/1-js/09-classes/01-class/article.md
@@ -218,7 +218,7 @@ function makeClass(phrase) {
return class {
sayHi() {
alert(phrase);
- };
+ }
};
}
diff --git a/1-js/09-classes/02-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md
index 69ca4eab8e..d84ab44252 100644
--- a/1-js/09-classes/02-class-inheritance/article.md
+++ b/1-js/09-classes/02-class-inheritance/article.md
@@ -76,8 +76,8 @@ For instance, a function call that generates the parent class:
```js run
function f(phrase) {
return class {
- sayHi() { alert(phrase) }
- }
+ sayHi() { alert(phrase); }
+ };
}
*!*
@@ -300,7 +300,7 @@ Consider this example:
```js run
class Animal {
- name = 'animal'
+ name = 'animal';
constructor() {
alert(this.name); // (*)
diff --git a/1-js/09-classes/06-instanceof/article.md b/1-js/09-classes/06-instanceof/article.md
index dd3d61ca64..6308181889 100644
--- a/1-js/09-classes/06-instanceof/article.md
+++ b/1-js/09-classes/06-instanceof/article.md
@@ -2,7 +2,7 @@
The `instanceof` operator allows to check whether an object belongs to a certain class. It also takes inheritance into account.
-Such a check may be necessary in many cases. Here we'll use it for building a *polymorphic* function, the one that treats arguments differently depending on their type.
+Such a check may be necessary in many cases. For example, it can be used for building a *polymorphic* function, the one that treats arguments differently depending on their type.
## The instanceof operator [#ref-instanceof]
diff --git a/1-js/11-async/01-callbacks/article.md b/1-js/11-async/01-callbacks/article.md
index 9d1a260d52..344d92b742 100644
--- a/1-js/11-async/01-callbacks/article.md
+++ b/1-js/11-async/01-callbacks/article.md
@@ -146,7 +146,7 @@ loadScript('/my/script.js', function(script) {
});
*/!*
- })
+ });
});
```
@@ -223,7 +223,7 @@ loadScript('1.js', function(error, script) {
});
}
- })
+ });
}
});
```
@@ -256,7 +256,7 @@ loadScript('1.js', function(error, script) {
}
});
}
- })
+ });
}
});
-->
@@ -296,7 +296,7 @@ function step3(error, script) {
} else {
// ...continue after all scripts are loaded (*)
}
-};
+}
```
See? It does the same, and there's no deep nesting now because we made every action a separate top-level function.
diff --git a/1-js/11-async/03-promise-chaining/article.md b/1-js/11-async/03-promise-chaining/article.md
index 9f3b60f3a5..78d381a94b 100644
--- a/1-js/11-async/03-promise-chaining/article.md
+++ b/1-js/11-async/03-promise-chaining/article.md
@@ -265,7 +265,7 @@ fetch('/article/promise-chaining/user.json')
Now let's do something with the loaded user.
-For instance, we can make one more requests to GitHub, load the user profile and show the avatar:
+For instance, we can make one more request to GitHub, load the user profile and show the avatar:
```js run
// Make a request for user.json
diff --git a/1-js/11-async/05-promise-api/article.md b/1-js/11-async/05-promise-api/article.md
index 191f6ed210..5b4930beee 100644
--- a/1-js/11-async/05-promise-api/article.md
+++ b/1-js/11-async/05-promise-api/article.md
@@ -176,15 +176,14 @@ So for each promise we get its status and `value/error`.
If the browser doesn't support `Promise.allSettled`, it's easy to polyfill:
```js
-if(!Promise.allSettled) {
- Promise.allSettled = function(promises) {
- return Promise.all(promises.map(p => Promise.resolve(p).then(value => ({
- status: 'fulfilled',
- value
- }), reason => ({
- status: 'rejected',
- reason
- }))));
+if (!Promise.allSettled) {
+ const rejectHandler = reason => ({ status: 'rejected', reason });
+
+ const resolveHandler = value => ({ status: 'fulfilled', value });
+
+ Promise.allSettled = function (promises) {
+ const convertedPromises = promises.map(p => Promise.resolve(p).then(resolveHandler, rejectHandler));
+ return Promise.all(convertedPromises);
};
}
```
diff --git a/1-js/11-async/06-promisify/article.md b/1-js/11-async/06-promisify/article.md
index 4ef6225465..ac94998998 100644
--- a/1-js/11-async/06-promisify/article.md
+++ b/1-js/11-async/06-promisify/article.md
@@ -4,6 +4,8 @@
Such transformations are often required in real-life, as many functions and libraries are callback-based. But promises are more convenient, so it makes sense to promisify them.
+For better understanding, let's see an example.
+
For instance, we have `loadScript(src, callback)` from the chapter .
```js run
@@ -21,35 +23,42 @@ function loadScript(src, callback) {
// loadScript('path/script.js', (err, script) => {...})
```
-Let's promisify it. The new `loadScriptPromise(src)` function achieves the same result, but it accepts only `src` (no `callback`) and returns a promise.
+The function loads a script with the given `src`, and then calls `callback(err)` in case of an error, or `callback(null, script)` in case of successful loading. That's a widespread agreement for using callbacks, we saw it before.
+
+Let's promisify it.
+
+We'll make a new function `loadScriptPromise(src)`, that does the same (loads the script), but returns a promise instead of using callbacks.
+
+In other words, we pass it only `src` (no `callback`) and get a promise in return, that resolves with `script` when the load is successful, and rejects with the error otherwise.
+Here it is:
```js
let loadScriptPromise = function(src) {
return new Promise((resolve, reject) => {
loadScript(src, (err, script) => {
- if (err) reject(err)
+ if (err) reject(err);
else resolve(script);
});
- })
-}
+ });
+};
// usage:
// loadScriptPromise('path/script.js').then(...)
```
-Now `loadScriptPromise` fits well in promise-based code.
+As we can see, the new function is a wrapper around the original `loadScript` function. It calls it providing its own callback that translates to promise `resolve/reject`.
-As we can see, it delegates all the work to the original `loadScript`, providing its own callback that translates to promise `resolve/reject`.
+Now `loadScriptPromise` fits well in promise-based code. If we like promises more than callbacks (and soon we'll see more reasons for that), then we will use it instead.
-In practice we'll probably need to promisify many functions, so it makes sense to use a helper. We'll call it `promisify(f)`: it accepts a to-promisify function `f` and returns a wrapper function.
+In practice we may need to promisify more than one function, so it makes sense to use a helper.
-That wrapper does the same as in the code above: returns a promise and passes the call to the original `f`, tracking the result in a custom callback:
+We'll call it `promisify(f)`: it accepts a to-promisify function `f` and returns a wrapper function.
```js
function promisify(f) {
- return function (...args) { // return a wrapper-function
+ return function (...args) { // return a wrapper-function (*)
return new Promise((resolve, reject) => {
- function callback(err, result) { // our custom callback for f
+ function callback(err, result) { // our custom callback for f (**)
if (err) {
reject(err);
} else {
@@ -62,18 +71,25 @@ function promisify(f) {
f.call(this, ...args); // call the original function
});
};
-};
+}
// usage:
let loadScriptPromise = promisify(loadScript);
loadScriptPromise(...).then(...);
```
-Here we assume that the original function expects a callback with two arguments `(err, result)`. That's what we encounter most often. Then our custom callback is in exactly the right format, and `promisify` works great for such a case.
+The code may look a bit complex, but it's essentially the same that we wrote above, while promisifying `loadScript` function.
+
+A call to `promisify(f)` returns a wrapper around `f` `(*)`. That wrapper returns a promise and forwards the call to the original `f`, tracking the result in the custom callback `(**)`.
+
+Here, `promisify` assumes that the original function expects a callback with exactly two arguments `(err, result)`. That's what we encounter most often. Then our custom callback is in exactly the right format, and `promisify` works great for such a case.
But what if the original `f` expects a callback with more arguments `callback(err, res1, res2, ...)`?
-Here's a more advanced version of `promisify`: if called as `promisify(f, true)`, the promise result will be an array of callback results `[res1, res2, ...]`:
+We can improve our helper. Let's make a more advanced version of `promisify`.
+
+- When called as `promisify(f)` it should work similar to the version above.
+- When called as `promisify(f, true)`, it should return the promise that resolves with the array of callback results. That's exactly for callbacks with many arguments.
```js
// promisify(f, true) to get array of results
@@ -94,13 +110,15 @@ function promisify(f, manyArgs = false) {
f.call(this, ...args);
});
};
-};
+}
// usage:
f = promisify(f, true);
-f(...).then(arrayOfResults => ..., err => ...)
+f(...).then(arrayOfResults => ..., err => ...);
```
+As you can see it's essentially the same as above, but `resolve` is called with only one or all arguments depending on whether `manyArgs` is truthy.
+
For more exotic callback formats, like those without `err` at all: `callback(result)`, we can promisify such functions manually without using the helper.
There are also modules with a bit more flexible promisification functions, e.g. [es6-promisify](https://github.com/digitaldesignlabs/es6-promisify). In Node.js, there's a built-in `util.promisify` function for that.
diff --git a/1-js/11-async/08-async-await/01-rewrite-async/task.md b/1-js/11-async/08-async-await/01-rewrite-async/task.md
index e2fd375d97..a04b4ff94f 100644
--- a/1-js/11-async/08-async-await/01-rewrite-async/task.md
+++ b/1-js/11-async/08-async-await/01-rewrite-async/task.md
@@ -12,7 +12,7 @@ function loadJson(url) {
} else {
throw new Error(response.status);
}
- })
+ });
}
loadJson('no-such-user.json')
diff --git a/1-js/11-async/08-async-await/02-rewrite-async-2/task.md b/1-js/11-async/08-async-await/02-rewrite-async-2/task.md
index a5c1c03a2d..13d625d2a8 100644
--- a/1-js/11-async/08-async-await/02-rewrite-async-2/task.md
+++ b/1-js/11-async/08-async-await/02-rewrite-async-2/task.md
@@ -1,7 +1,7 @@
# Rewrite "rethrow" with async/await
-Below you can find the "rethrow" example from the chapter . Rewrite it using `async/await` instead of `.then/catch`.
+Below you can find the "rethrow" example. Rewrite it using `async/await` instead of `.then/catch`.
And get rid of the recursion in favour of a loop in `demoGithubUser`: with `async/await` that becomes easy to do.
@@ -22,7 +22,7 @@ function loadJson(url) {
} else {
throw new HttpError(response);
}
- })
+ });
}
// Ask for a user name until github returns a valid user
diff --git a/1-js/11-async/08-async-await/03-async-from-regular/task.md b/1-js/11-async/08-async-await/03-async-from-regular/task.md
index 18d0e2ce75..ca7c186ff2 100644
--- a/1-js/11-async/08-async-await/03-async-from-regular/task.md
+++ b/1-js/11-async/08-async-await/03-async-from-regular/task.md
@@ -1,7 +1,7 @@
# Call async from non-async
-We have a "regular" function. How to call `async` from it and use its result?
+We have a "regular" function called `f`. How can you call the `async` function `wait()` and use its result inside of `f`?
```js
async function wait() {
@@ -11,7 +11,7 @@ async function wait() {
}
function f() {
- // ...what to write here?
+ // ...what should you write here?
// we need to call async wait() and wait to get 10
// remember, we can't use "await"
}
diff --git a/1-js/11-async/08-async-await/article.md b/1-js/11-async/08-async-await/article.md
index 29bfcaf516..176c691e91 100644
--- a/1-js/11-async/08-async-await/article.md
+++ b/1-js/11-async/08-async-await/article.md
@@ -156,7 +156,7 @@ class Thenable {
// resolve with this.num*2 after 1000ms
setTimeout(() => resolve(this.num * 2), 1000); // (*)
}
-};
+}
async function f() {
// waits for 1 second, then result becomes 2
diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/article.md b/1-js/12-generators-iterators/2-async-iterators-generators/article.md
index 10375f6352..00a56b9c31 100644
--- a/1-js/12-generators-iterators/2-async-iterators-generators/article.md
+++ b/1-js/12-generators-iterators/2-async-iterators-generators/article.md
@@ -301,7 +301,7 @@ Now values come with a delay of 1 second between them.
```smart
Technically, we can add both `Symbol.iterator` and `Symbol.asyncIterator` to the object, so it's both synchronously (`for..of`) and asynchronously (`for await..of`) iterable.
-In practice though, that would be an weird thing to do.
+In practice though, that would be a weird thing to do.
```
## Real-life example: paginated data
@@ -363,7 +363,7 @@ More explanations about how it works:
- The initial URL is `https://api.github.com/repos//commits`, and the next page will be in the `Link` header of the response.
- The `fetch` method allows us to supply authorization and other headers if needed -- here GitHub requires `User-Agent`.
2. The commits are returned in JSON format.
-3. We should get the next page URL from the `Link` header of the response. It has a special format, so we use a regular expression for that.
+3. We should get the next page URL from the `Link` header of the response. It has a special format, so we use a regular expression for that (we will lern this feature in [Regular expressions](info:regular-expressions)).
- The next page URL may look like `https://api.github.com/repositories/93253246/commits?page=2`. It's generated by GitHub itself.
4. Then we yield the received commits one by one, and when they finish, the next `while(url)` iteration will trigger, making one more request.
diff --git a/1-js/13-modules/01-modules-intro/article.md b/1-js/13-modules/01-modules-intro/article.md
index e9e1fc249a..9afe0fdaa9 100644
--- a/1-js/13-modules/01-modules-intro/article.md
+++ b/1-js/13-modules/01-modules-intro/article.md
@@ -260,7 +260,7 @@ Compare to regular script below:
diff --git a/1-js/13-modules/02-import-export/article.md b/1-js/13-modules/02-import-export/article.md
index 4bd41a1689..497205f421 100644
--- a/1-js/13-modules/02-import-export/article.md
+++ b/1-js/13-modules/02-import-export/article.md
@@ -321,7 +321,7 @@ export {default as User} from './user.js'; // re-export default
Why would that be needed? Let's see a practical use case.
-Imagine, we're writing a "package": a folder with a lot of modules, with some of the functionality exported outside (tools like NPM allow us to publish and distribute such packages), and many modules are just "helpers", for internal use in other package modules.
+Imagine, we're writing a "package": a folder with a lot of modules, with some of the functionality exported outside (tools like NPM allow us to publish and distribute such packages, but we don't have to use them), and many modules are just "helpers", for internal use in other package modules.
The file structure could be like this:
```
@@ -378,7 +378,7 @@ export {default as User} from './user.js';
The default export needs separate handling when re-exporting.
-Let's say we have `user.js`, and we'd like to re-export class `User` from it:
+Let's say we have `user.js` with the `export default class User` and would like to re-export it:
```js
// 📁 user.js
@@ -387,7 +387,9 @@ export default class User {
}
```
-1. `export User from './user.js'` won't work. What can go wrong?... But that's a syntax error!
+We can come across two problems with it:
+
+1. `export User from './user.js'` won't work. That would lead to a syntax error.
To re-export the default export, we have to write `export {default as User}`, as in the example above.
@@ -399,7 +401,7 @@ export default class User {
export {default} from './user.js'; // to re-export the default export
```
-Such oddities of re-exporting the default export are one of the reasons why some developers don't like them.
+Such oddities of re-exporting a default export are one of the reasons why some developers don't like default exports and prefer named ones.
## Summary
diff --git a/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md b/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md
index 357a573134..9db69cb2fa 100644
--- a/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md
+++ b/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md
@@ -19,5 +19,5 @@ function wrap(target) {
user = wrap(user);
alert(user.name); // John
-alert(user.age); // ReferenceError: Property doesn't exist "age"
+alert(user.age); // ReferenceError: Property doesn't exist: "age"
```
diff --git a/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md b/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md
index d7093c0c3e..47985e1a76 100644
--- a/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md
+++ b/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md
@@ -27,6 +27,6 @@ user = wrap(user);
alert(user.name); // John
*!*
-alert(user.age); // ReferenceError: Property doesn't exist "age"
+alert(user.age); // ReferenceError: Property doesn't exist: "age"
*/!*
```
diff --git a/1-js/99-js-misc/01-proxy/article.md b/1-js/99-js-misc/01-proxy/article.md
index 0711fd33a7..b1c351d3ac 100644
--- a/1-js/99-js-misc/01-proxy/article.md
+++ b/1-js/99-js-misc/01-proxy/article.md
@@ -39,7 +39,7 @@ As there are no traps, all operations on `proxy` are forwarded to `target`.
As we can see, without any traps, `proxy` is a transparent wrapper around `target`.
-
+
`Proxy` is a special "exotic object". It doesn't have own properties. With an empty `handler` it transparently forwards operations to `target`.
@@ -335,7 +335,7 @@ let user = {
_password: "secret"
};
-alert(user._password); // secret
+alert(user._password); // secret
```
Let's use proxies to prevent any access to properties starting with `_`.
@@ -376,7 +376,7 @@ user = new Proxy(user, {
},
*!*
deleteProperty(target, prop) { // to intercept property deletion
-*/!*
+*/!*
if (prop.startsWith('_')) {
throw new Error("Access denied");
} else {
@@ -437,7 +437,7 @@ user = {
```
-A call to `user.checkPassword()` call gets proxied `user` as `this` (the object before dot becomes `this`), so when it tries to access `this._password`, the `get` trap activates (it triggers on any property read) and throws an error.
+A call to `user.checkPassword()` gets proxied `user` as `this` (the object before dot becomes `this`), so when it tries to access `this._password`, the `get` trap activates (it triggers on any property read) and throws an error.
So we bind the context of object methods to the original object, `target`, in the line `(*)`. Then their future calls will use `target` as `this`, without any traps.
diff --git a/1-js/99-js-misc/04-reference-type/3-why-this/solution.md b/1-js/99-js-misc/04-reference-type/3-why-this/solution.md
index 31ea4ff88b..e4ee787489 100644
--- a/1-js/99-js-misc/04-reference-type/3-why-this/solution.md
+++ b/1-js/99-js-misc/04-reference-type/3-why-this/solution.md
@@ -5,7 +5,7 @@ Here's the explanations.
2. The same, parentheses do not change the order of operations here, the dot is first anyway.
-3. Here we have a more complex call `(expression).method()`. The call works as if it were split into two lines:
+3. Here we have a more complex call `(expression)()`. The call works as if it were split into two lines:
```js no-beautify
f = obj.go; // calculate the expression
@@ -14,7 +14,7 @@ Here's the explanations.
Here `f()` is executed as a function, without `this`.
-4. The similar thing as `(3)`, to the left of the dot `.` we have an expression.
+4. The similar thing as `(3)`, to the left of the parentheses `()` we have an expression.
To explain the behavior of `(3)` and `(4)` we need to recall that property accessors (dot or square brackets) return a value of the Reference Type.
diff --git a/1-js/99-js-misc/04-reference-type/article.md b/1-js/99-js-misc/04-reference-type/article.md
index c680c17f99..227253436e 100644
--- a/1-js/99-js-misc/04-reference-type/article.md
+++ b/1-js/99-js-misc/04-reference-type/article.md
@@ -93,7 +93,7 @@ Reference type is a special "intermediary" internal type, with the purpose to pa
Any other operation like assignment `hi = user.hi` discards the reference type as a whole, takes the value of `user.hi` (a function) and passes it on. So any further operation "loses" `this`.
-So, as the result, the value of `this` is only passed the right way if the function is called directly using a dot `obj.method()` or square brackets `obj['method']()` syntax (they do the same here). Later in this tutorial, we will learn various ways to solve this problem such as [func.bind()](/bind#solution-2-bind).
+So, as the result, the value of `this` is only passed the right way if the function is called directly using a dot `obj.method()` or square brackets `obj['method']()` syntax (they do the same here). There are various ways to solve this problem such as [func.bind()](/bind#solution-2-bind).
## Summary
diff --git a/2-ui/1-document/04-searching-elements-dom/article.md b/2-ui/1-document/04-searching-elements-dom/article.md
index f5ab0b785e..70a8bae4c1 100644
--- a/2-ui/1-document/04-searching-elements-dom/article.md
+++ b/2-ui/1-document/04-searching-elements-dom/article.md
@@ -71,7 +71,7 @@ If there are multiple elements with the same `id`, then the behavior of methods
```
```warn header="Only `document.getElementById`, not `anyElem.getElementById`"
-The method `getElementById` that can be called only on `document` object. It looks for the given `id` in the whole document.
+The method `getElementById` can be called only on `document` object. It looks for the given `id` in the whole document.
```
## querySelectorAll [#querySelectorAll]
@@ -363,7 +363,7 @@ There are 6 main methods to search for nodes in DOM:
-By far the most used are `querySelector` and `querySelectorAll`, but `getElementBy*` can be sporadically helpful or found in the old scripts.
+By far the most used are `querySelector` and `querySelectorAll`, but `getElement(s)By*` can be sporadically helpful or found in the old scripts.
Besides that:
diff --git a/2-ui/1-document/05-basic-dom-node-properties/article.md b/2-ui/1-document/05-basic-dom-node-properties/article.md
index cea166e8d1..fc3bf6525b 100644
--- a/2-ui/1-document/05-basic-dom-node-properties/article.md
+++ b/2-ui/1-document/05-basic-dom-node-properties/article.md
@@ -198,7 +198,7 @@ In XML mode the case is kept "as is". Nowadays XML mode is rarely used.
## innerHTML: the contents
-The [innerHTML](https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML) property allows to get the HTML inside the element as a string.
+The [innerHTML](https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin) property allows to get the HTML inside the element as a string.
We can also modify it. So it's one of the most powerful ways to change the page.
diff --git a/2-ui/1-document/06-dom-attributes-and-properties/article.md b/2-ui/1-document/06-dom-attributes-and-properties/article.md
index bcbf074cee..e39a542564 100644
--- a/2-ui/1-document/06-dom-attributes-and-properties/article.md
+++ b/2-ui/1-document/06-dom-attributes-and-properties/article.md
@@ -298,7 +298,7 @@ For instance, here for the order state the attribute `order-state` is used:
```
-Why would using an attribute be preferable to having classes like `.order-state-new`, `.order-state-pending`, `order-state-canceled`?
+Why would using an attribute be preferable to having classes like `.order-state-new`, `.order-state-pending`, `.order-state-canceled`?
Because an attribute is more convenient to manage. The state can be changed as easy as:
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 e203a4eb4a..5d854a59fd 100644
--- a/2-ui/2-events/02-bubbling-and-capturing/article.md
+++ b/2-ui/2-events/02-bubbling-and-capturing/article.md
@@ -206,7 +206,7 @@ When an event happens -- the most nested element where it happens gets labeled a
- Then the event moves down from the document root to `event.target`, calling handlers assigned with `addEventListener(..., true)` on the way (`true` is a shorthand for `{capture: true}`).
- Then handlers are called on the target element itself.
-- Then the event bubbles up from `event.target` to the root, calling handlers assigned using `on` and `addEventListener` without the 3rd argument or with the 3rd argument `false/{capture:false}`.
+- Then the event bubbles up from `event.target` to the root, calling handlers assigned using `on`, HTML attributes and `addEventListener` without the 3rd argument or with the 3rd argument `false/{capture:false}`.
Each handler can access `event` object properties:
diff --git a/2-ui/2-events/03-event-delegation/article.md b/2-ui/2-events/03-event-delegation/article.md
index df086f24b5..41df9f0790 100644
--- a/2-ui/2-events/03-event-delegation/article.md
+++ b/2-ui/2-events/03-event-delegation/article.md
@@ -5,7 +5,7 @@ Capturing and bubbling allow us to implement one of most powerful event handling
The idea is that if we have a lot of elements handled in a similar way, then instead of assigning a handler to each of them -- we put a single handler on their common ancestor.
-In the handler we get `event.target`, see where the event actually happened and handle it.
+In the handler we get `event.target` to see where the event actually happened and handle it.
Let's see an example -- the [Ba-Gua diagram](http://en.wikipedia.org/wiki/Ba_gua) reflecting the ancient Chinese philosophy.
diff --git a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md
index 6a2d24ad23..377e7703a0 100644
--- a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md
+++ b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md
@@ -145,7 +145,7 @@ let analyticsData = { /* object with gathered data */ };
window.addEventListener("unload", function() {
navigator.sendBeacon("/analytics", JSON.stringify(analyticsData));
-};
+});
```
- The request is sent as POST.
diff --git a/2-ui/5-loading/02-script-async-defer/article.md b/2-ui/5-loading/02-script-async-defer/article.md
index 24af956dc8..2f9d45e9c3 100644
--- a/2-ui/5-loading/02-script-async-defer/article.md
+++ b/2-ui/5-loading/02-script-async-defer/article.md
@@ -37,7 +37,7 @@ Luckily, there are two `