diff --git a/1-js/04-object-basics/04-object-methods/3-why-this/task.md b/1-js/04-object-basics/04-object-methods/3-why-this/task.md index f22de29cc..e2c073f62 100644 --- a/1-js/04-object-basics/04-object-methods/3-why-this/task.md +++ b/1-js/04-object-basics/04-object-methods/3-why-this/task.md @@ -4,7 +4,7 @@ importance: 3 # Explain the value of "this" -In the code below we intend to call `user.go()` method 4 times in a row. +In the code below we intend to call `obj.go()` method 4 times in a row. But calls `(1)` and `(2)` works differently from `(3)` and `(4)`. Why? diff --git a/1-js/05-data-types/05-array-methods/4-sort-back/task.md b/1-js/05-data-types/05-array-methods/4-sort-back/task.md index 05a08aad0..0e3eeab76 100644 --- a/1-js/05-data-types/05-array-methods/4-sort-back/task.md +++ b/1-js/05-data-types/05-array-methods/4-sort-back/task.md @@ -2,12 +2,12 @@ importance: 4 --- -# Sort in the reverse order +# Sort in decreasing order ```js let arr = [5, 2, 1, -10, 8]; -// ... your code to sort it in the reverse order +// ... your code to sort it in decreasing order alert( arr ); // 8, 5, 2, 1, -10 ``` 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 eb88c56ae..50b25d8bd 100644 --- a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md +++ b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md @@ -288,7 +288,7 @@ For server-side JavaScript, that limitation does not exist, and there exist othe - Methods `setTimeout(func, delay, ...args)` and `setInterval(func, delay, ...args)` allow us to run the `func` once/regularly after `delay` milliseconds. - To cancel the execution, we should call `clearTimeout/clearInterval` with the value returned by `setTimeout/setInterval`. -- Nested `setTimeout` calls is a more flexible alternative to `setInterval`, allowing us to set the time *between* executions more precisely. +- 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. diff --git a/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md b/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md index f8b83d7a2..c90851c2b 100644 --- a/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md +++ b/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md @@ -8,7 +8,7 @@ The task is a little more complex variant of . The `user` object was modified. Now instead of two functions `loginOk/loginFail`, it has a single function `user.login(true/false)`. -What to pass `askPassword` in the code below, so that it calls `user.login(true)` as `ok` and `user.login(false)` as `fail`? +What should we pass `askPassword` in the code below, so that it calls `user.login(true)` as `ok` and `user.login(false)` as `fail`? ```js function askPassword(ok, fail) { diff --git a/1-js/06-advanced-functions/10-bind/article.md b/1-js/06-advanced-functions/10-bind/article.md index b8c545b1c..20f2e098f 100644 --- a/1-js/06-advanced-functions/10-bind/article.md +++ b/1-js/06-advanced-functions/10-bind/article.md @@ -98,7 +98,7 @@ Functions provide a built-in method [bind](mdn:js/Function/bind) that allows to The basic syntax is: ```js -// more complex syntax will be little later +// more complex syntax will come a little later let boundFunc = func.bind(context); ``` 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 1d6b04394..f5caeaece 100644 --- a/1-js/06-advanced-functions/12-arrow-functions/article.md +++ b/1-js/06-advanced-functions/12-arrow-functions/article.md @@ -118,9 +118,9 @@ Here we had to create additional variables `args` and `ctx` so that the function Arrow functions: -- Do not have `this`. -- Do not have `arguments`. -- Can't be called with `new`. -- (They also don't have `super`, but we didn't study it. Will be in the chapter ). +- Do not have `this` +- Do not have `arguments` +- Can't be called with `new` +- They also don't have `super`, but we didn't study it yet. We will on the chapter -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. +That's because they are meant for short pieces of code that do not have their own "context", but rather work in the current one. And they really shine in that use case. diff --git a/1-js/07-object-properties/01-property-descriptors/article.md b/1-js/07-object-properties/01-property-descriptors/article.md index 9f8f85d9c..e894f0662 100644 --- a/1-js/07-object-properties/01-property-descriptors/article.md +++ b/1-js/07-object-properties/01-property-descriptors/article.md @@ -3,7 +3,7 @@ As we know, objects can store properties. -Till now, a property was a simple "key-value" pair to us. But an object property is actually a more flexible and powerful thing. +Until now, a property was a simple "key-value" pair to us. But an object property is actually a more flexible and powerful thing. In this chapter we'll study additional configuration options, and in the next we'll see how to invisibly turn them into getter/setter functions. @@ -134,7 +134,7 @@ let user = { }; Object.defineProperty(user, "name", { *!* value: "John", - // for new properties need to explicitly list what's true + // for new properties we need to explicitly list what's true enumerable: true, configurable: true */!* @@ -148,7 +148,7 @@ user.name = "Pete"; // Error Now let's add a custom `toString` to `user`. -Normally, a built-in `toString` for objects is non-enumerable, it does not show up in `for..in`. But if we add `toString` of our own, then by default it shows up in `for..in`, like this: +Normally, a built-in `toString` for objects is non-enumerable, it does not show up in `for..in`. But if we add a `toString` of our own, then by default it shows up in `for..in`, like this: ```js run let user = { @@ -162,7 +162,7 @@ let user = { 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: +If we don't like it, then we can set `enumerable:false`. Then it won't appear in a `for..in` loop, just like the built-in one: ```js run let user = { diff --git a/1-js/07-object-properties/02-property-accessors/article.md b/1-js/07-object-properties/02-property-accessors/article.md index dc541b6da..726529c5b 100644 --- a/1-js/07-object-properties/02-property-accessors/article.md +++ b/1-js/07-object-properties/02-property-accessors/article.md @@ -3,7 +3,7 @@ There are two kinds of properties. -The first kind is *data properties*. We already know how to work with them. All properties that we've been using till now were data properties. +The first kind is *data properties*. We already know how to work with them. All properties that we've been using until now were data properties. The second type of properties is something new. It's *accessor properties*. They are essentially functions that work on getting and setting a value, but look like regular properties to an external code. @@ -189,9 +189,9 @@ Technically, external code is able to access the name directly by using `user._n ## Using for compatibility -One of the great uses of accessors -- they allow to take control over a "regular" data property at any moment by replacing it with getter and setter and tweak its behavior. +One of the great uses of accessors is that they allow to take control over a "regular" data property at any moment by replacing it with a getter and a setter and tweak its behavior. -Imagine, we started implementing user objects using data properties `name` and `age`: +Imagine we started implementing user objects using data properties `name` and `age`: ```js function User(name, age) { diff --git a/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md b/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md index 421b57e0a..bc2db47fe 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md +++ b/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md @@ -6,7 +6,7 @@ importance: 5 The task has two parts. -We have objects: +Given the following objects: ```js let head = { diff --git a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md index b37499bad..ed8482c07 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md +++ b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md @@ -2,7 +2,7 @@ importance: 5 --- -# Where it writes? +# Where does it write? We have `rabbit` inheriting from `animal`. diff --git a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md index 6f9fb279e..50171123d 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md +++ b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Why two hamsters are full? +# Why are both hamsters full? We have two hamsters: `speedy` and `lazy` inheriting from the general `hamster` object. -When we feed one of them, the other one is also full. Why? How to fix it? +When we feed one of them, the other one is also full. Why? How can we fix it? ```js run let hamster = { diff --git a/1-js/08-prototypes/01-prototype-inheritance/article.md b/1-js/08-prototypes/01-prototype-inheritance/article.md index 8da5fb76e..69e7c5f5c 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/article.md +++ b/1-js/08-prototypes/01-prototype-inheritance/article.md @@ -34,7 +34,7 @@ rabbit.__proto__ = animal; ```smart header="`__proto__` is a historical getter/setter for `[[Prototype]]`" Please note that `__proto__` is *not the same* as `[[Prototype]]`. That'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. +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. ``` @@ -203,7 +203,7 @@ Here in the line `(*)` the property `admin.fullName` has a getter in the prototy ## The value of "this" -An interesting question may arise in the example above: what's the value of `this` inside `set fullName(value)`? Where the properties `this.name` and `this.surname` are written: into `user` or `admin`? +An interesting question may arise in the example above: what's the value of `this` inside `set fullName(value)`? Where are the properties `this.name` and `this.surname` written: into `user` or `admin`? The answer is simple: `this` is not affected by prototypes at all. @@ -246,13 +246,13 @@ The resulting picture: ![](proto-animal-rabbit-walk-3.svg) -If we had other objects like `bird`, `snake` etc inheriting from `animal`, they would also gain access to methods of `animal`. But `this` in each method call would be the corresponding object, evaluated at the call-time (before dot), not `animal`. So when we write data into `this`, it is stored into these objects. +If we had other objects, like `bird`, `snake`, etc., inheriting from `animal`, they would also gain access to methods of `animal`. But `this` in each method call would be the corresponding object, evaluated at the call-time (before dot), not `animal`. So when we write data into `this`, it is stored into these objects. As a result, methods are shared, but the object state is not. ## for..in loop -The `for..in` loops over inherited properties too. +The `for..in` loop iterates over inherited properties too. For instance: @@ -267,7 +267,7 @@ let rabbit = { }; *!* -// Object.keys only return own keys +// Object.keys only returns own keys alert(Object.keys(rabbit)); // jumps */!* diff --git a/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md b/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md index 4b8522d3d..2838c125a 100644 --- a/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md +++ b/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md @@ -20,7 +20,7 @@ alert( rabbit.eats ); // true ``` -1. We added one more string (emphasized), what `alert` shows now? +1. We added one more string (emphasized). What will `alert` show now? ```js function Rabbit() {} @@ -54,7 +54,7 @@ alert( rabbit.eats ); // true alert( rabbit.eats ); // ? ``` -3. Like this (replaced one line)? +3. And like this (replaced one line)? ```js function Rabbit() {} diff --git a/1-js/08-prototypes/02-function-prototype/article.md b/1-js/08-prototypes/02-function-prototype/article.md index 29b3773eb..c106d1d90 100644 --- a/1-js/08-prototypes/02-function-prototype/article.md +++ b/1-js/08-prototypes/02-function-prototype/article.md @@ -2,7 +2,7 @@ Remember, new objects can be created with a constructor function, like `new F()`. -If `F.prototype` is an object, then `new` operator uses it to set `[[Prototype]]` for the new object. +If `F.prototype` is an object, then the `new` operator uses it to set `[[Prototype]]` for the new object. ```smart JavaScript had prototypal inheritance from the beginning. It was one of the core features of the language. @@ -158,9 +158,9 @@ Rabbit.prototype = { In this chapter we briefly described the way of setting a `[[Prototype]]` for objects created via a constructor function. Later we'll see more advanced programming patterns that rely on it. -Everything is quite simple, just few notes to make things clear: +Everything is quite simple, just a few notes to make things clear: -- The `F.prototype` property (don't mess with `[[Prototype]]`) sets `[[Prototype]]` of new objects when `new F()` is called. +- The `F.prototype` property (don't mistake it for `[[Prototype]]`) sets `[[Prototype]]` of new objects when `new F()` is called. - The value of `F.prototype` should be either an object or `null`: other values won't work. - The `"prototype"` property only has such a special effect when set on a constructor function, and invoked with `new`. diff --git a/1-js/08-prototypes/03-native-prototypes/article.md b/1-js/08-prototypes/03-native-prototypes/article.md index b50e779ec..378936c9a 100644 --- a/1-js/08-prototypes/03-native-prototypes/article.md +++ b/1-js/08-prototypes/03-native-prototypes/article.md @@ -99,12 +99,12 @@ alert(f.__proto__.__proto__ == Object.prototype); // true, inherit from objects The most intricate thing happens with strings, numbers and booleans. -As we remember, they are not objects. But if we try to access their properties, then temporary wrapper objects are created using built-in constructors `String`, `Number`, `Boolean`, they provide the methods and disappear. +As we remember, they are not objects. But if we try to access their properties, temporary wrapper objects are created using built-in constructors `String`, `Number` and `Boolean`. They provide the methods and disappear. These objects are created invisibly to us and most engines optimize them out, but the specification describes it exactly this way. Methods of these objects also reside in prototypes, available as `String.prototype`, `Number.prototype` and `Boolean.prototype`. ```warn header="Values `null` and `undefined` have no object wrappers" -Special values `null` and `undefined` stand apart. They have no object wrappers, so methods and properties are not available for them. And there are no corresponding prototypes too. +Special values `null` and `undefined` stand apart. They have no object wrappers, so methods and properties are not available for them. And there are no corresponding prototypes either. ``` ## Changing native prototypes [#native-prototype-change] @@ -129,9 +129,9 @@ So, generally, modifying a native prototype is considered a bad idea. **In modern programming, there is only one case where modifying native prototypes is approved. That's polyfilling.** -Polyfilling is a term for making a substitute for a method that exists in JavaScript specification, but is not yet supported by current JavaScript engine. +Polyfilling is a term for making a substitute for a method that exists in the JavaScript specification, but is not yet supported by a particular JavaScript engine. -Then we may implement it manually and populate the built-in prototype with it. +We may then implement it manually and populate the built-in prototype with it. For instance: @@ -144,7 +144,7 @@ if (!String.prototype.repeat) { // if there's no such method // actually, the code should be a little bit more complex than that // (the full algorithm is in the specification) - // but even an imperfect polyfill is often considered good enough for use + // but even an imperfect polyfill is often considered good enough return new Array(n + 1).join(this); }; } @@ -179,18 +179,18 @@ obj.join = Array.prototype.join; alert( obj.join(',') ); // Hello,world! ``` -It works, because the internal algorithm of the built-in `join` method only cares about the correct indexes and the `length` property, it doesn't check that the object is indeed the array. And many built-in methods are like that. +It works because the internal algorithm of the built-in `join` method only cares about the correct indexes and the `length` property. It doesn't check if the object is indeed an array. Many built-in methods are like that. Another possibility is to inherit by setting `obj.__proto__` to `Array.prototype`, so all `Array` methods are automatically available in `obj`. But that's impossible if `obj` already inherits from another object. Remember, we only can inherit from one object at a time. -Borrowing methods is flexible, it allows to mix functionality from different objects if needed. +Borrowing methods is flexible, it allows to mix functionalities from different objects if needed. ## Summary - All built-in objects follow the same pattern: - - The methods are stored in the prototype (`Array.prototype`, `Object.prototype`, `Date.prototype` etc). - - The object itself stores only the data (array items, object properties, the date). -- Primitives also store methods in prototypes of wrapper objects: `Number.prototype`, `String.prototype`, `Boolean.prototype`. Only `undefined` and `null` do not have wrapper objects. -- Built-in prototypes can be modified or populated with new methods. But it's not recommended to change them. Probably the only allowable case is when we add-in a new standard, but not yet supported by the engine JavaScript method. + - The methods are stored in the prototype (`Array.prototype`, `Object.prototype`, `Date.prototype`, etc.) + - The object itself stores only the data (array items, object properties, the date) +- Primitives also store methods in prototypes of wrapper objects: `Number.prototype`, `String.prototype` and `Boolean.prototype`. Only `undefined` and `null` do not have wrapper objects +- Built-in prototypes can be modified or populated with new methods. But it's not recommended to change them. The only allowable case is probably when we add-in a new standard, but it's not yet supported by the JavaScript engine diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md index a229483f1..80f5a956a 100644 --- a/1-js/08-prototypes/04-prototype-methods/article.md +++ b/1-js/08-prototypes/04-prototype-methods/article.md @@ -65,9 +65,9 @@ This call makes a truly exact copy of `obj`, including all properties: enumerabl ## Brief history -If we count all the ways to manage `[[Prototype]]`, there's a lot! Many ways to do the same! +If we count all the ways to manage `[[Prototype]]`, there are a lot! Many ways to do the same! -Why so? +Why? That's for historical reasons. @@ -80,9 +80,9 @@ As of now we have all these ways at our disposal. Why was `__proto__` replaced by the functions `getPrototypeOf/setPrototypeOf`? That's an interesting question, requiring us to understand why `__proto__` is bad. Read on to get the answer. ```warn header="Don't change `[[Prototype]]` on existing objects if speed matters" -Technically, we can get/set `[[Prototype]]` at any time. But usually we only set it once at the object creation time, and then do not modify: `rabbit` inherits from `animal`, and that is not going to change. +Technically, we can get/set `[[Prototype]]` at any time. But usually we only set it once at the object creation time and don't modify it anymore: `rabbit` inherits from `animal`, and that is not going to change. -And JavaScript engines are highly optimized for this. Changing a prototype "on-the-fly" with `Object.setPrototypeOf` or `obj.__proto__=` is a very slow operation, it breaks internal optimizations for object property access operations. So avoid it unless you know what you're doing, or JavaScript speed totally doesn't matter for you. +And JavaScript engines are highly optimized for this. Changing a prototype "on-the-fly" with `Object.setPrototypeOf` or `obj.__proto__=` is a very slow operation as it breaks internal optimizations for object property access operations. So avoid it unless you know what you're doing, or JavaScript speed totally doesn't matter for you. ``` ## "Very plain" objects [#very-plain] @@ -102,25 +102,25 @@ obj[key] = "some value"; alert(obj[key]); // [object Object], not "some value"! ``` -Here if the user types in `__proto__`, the assignment is ignored! +Here, if the user types in `__proto__`, the assignment is ignored! -That shouldn't surprise us. The `__proto__` property is special: it must be either an object or `null`, a string can not become a prototype. +That shouldn't surprise us. The `__proto__` property is special: it must be either an object or `null`. A string can not become a prototype. But we didn't *intend* to implement such behavior, right? We want to store key/value pairs, and the key named `"__proto__"` was not properly saved. So that's a bug! -Here the consequences are not terrible. But in other cases we may be assigning object values, and then the prototype may indeed be changed. As the result, the execution will go wrong in totally unexpected ways. +Here the consequences are not terrible. But in other cases we may be assigning object values, and then the prototype may indeed be changed. As a result, the execution will go wrong in totally unexpected ways. What's worse -- usually developers do not think about such possibility at all. That makes such bugs hard to notice and even turn them into vulnerabilities, especially when JavaScript is used on server-side. Unexpected things also may happen when assigning to `toString`, which is a function by default, and to other built-in methods. -How to avoid the problem? +How can we avoid this problem? First, we can just switch to using `Map`, then everything's fine. -But `Object` also can serve us well here, because language creators gave thought to that problem long ago. +But `Object` can also serve us well here, because language creators gave thought to that problem long ago. -The `__proto__` is not a property of an object, but an accessor property of `Object.prototype`: +`__proto__` is not a property of an object, but an accessor property of `Object.prototype`: ![](object-prototype-2.svg) @@ -147,7 +147,7 @@ alert(obj[key]); // "some value" So, there is no inherited getter/setter for `__proto__`. Now it is processed as a regular data property, so the example above works right. -We can call such object "very plain" or "pure dictionary objects", because they are even simpler than regular plain object `{...}`. +We can call such objects "very plain" or "pure dictionary" objects, because they are even simpler than the regular plain object `{...}`. A downside is that such objects lack any built-in object methods, e.g. `toString`: @@ -174,13 +174,13 @@ alert(Object.keys(chineseDictionary)); // hello,bye ## Summary -Modern methods to setup and directly access the prototype are: +Modern methods to set up and directly access the prototype are: -- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` (can be `null`) and optional property descriptors. +- [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). -The built-in `__proto__` getter/setter is unsafe if we'd want to put user-generated keys in to 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. +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. So we can either use `Object.create(null)` to create a "very plain" object without `__proto__`, or stick to `Map` objects for that. @@ -200,6 +200,6 @@ Other methods: - [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) -- returns an array of all own symbolic keys. - [Object.getOwnPropertyNames(obj)](mdn:js/Object/getOwnPropertyNames) -- returns an array of all own string keys. - [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) -- returns an array of all own keys. -- [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): it returns `true` if `obj` has its own (not inherited) key named `key`. +- [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): returns `true` if `obj` has its own (not inherited) key named `key`. -All methods that return object properties (like `Object.keys` and others) -- return "own" properties. If we want inherited ones, then we can use `for..in`. +All methods that return object properties (like `Object.keys` and others) -- return "own" properties. If we want inherited ones, we can use `for..in`. diff --git a/1-js/09-classes/01-class/article.md b/1-js/09-classes/01-class/article.md index d6c729d25..4aaf52bd4 100644 --- a/1-js/09-classes/01-class/article.md +++ b/1-js/09-classes/01-class/article.md @@ -68,7 +68,7 @@ So, what exactly is a `class`? That's not an entirely new language-level entity, Let's unveil any magic and see what a class really is. That'll help in understanding many complex aspects. -In JavaScript, a class is a kind of a function. +In JavaScript, a class is a kind of function. Here, take a look: @@ -179,7 +179,7 @@ Besides, `class` syntax brings many other features that we'll explore later. ## Class Expression -Just like functions, classes can be defined inside another expression, passed around, returned, assigned etc. +Just like functions, classes can be defined inside another expression, passed around, returned, assigned, etc. Here's an example of a class expression: @@ -344,6 +344,6 @@ class MyClass { } ``` -`MyClass` is technically a function (the one that we provide as `constructor`), while methods, getters and settors are written to `MyClass.prototype`. +`MyClass` is technically a function (the one that we provide as `constructor`), while methods, getters and setters are written to `MyClass.prototype`. In the next chapters we'll learn more about classes, including inheritance and other features. diff --git a/1-js/09-classes/02-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md index d1685f20a..9f5b484bc 100644 --- a/1-js/09-classes/02-class-inheritance/article.md +++ b/1-js/09-classes/02-class-inheritance/article.md @@ -66,7 +66,7 @@ For instance, to find `rabbit.run` method, the engine checks (bottom-up on the p 2. Its prototype, that is `Rabbit.prototype` (has `hide`, but not `run`). 3. Its prototype, that is (due to `extends`) `Animal.prototype`, that finally has the `run` method. -As we can recall from the chapter , JavaScript itself uses prototypal inheritance for build-in objects. E.g. `Date.prototype.[[Prototype]]` is `Object.prototype`. That's why dates have access to generic object methods. +As we can recall from the chapter , JavaScript itself uses prototypal inheritance for built-in objects. E.g. `Date.prototype.[[Prototype]]` is `Object.prototype`. That's why dates have access to generic object methods. ````smart header="Any expression is allowed after `extends`" Class syntax allows to specify not just a class, but any expression after `extends`. @@ -181,7 +181,7 @@ setTimeout(function() { super.stop() }, 1000); With constructors it gets a little bit tricky. -Till now, `Rabbit` did not have its own `constructor`. +Until now, `Rabbit` did not have its own `constructor`. According to the [specification](https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation), if a class extends another class and has no `constructor`, then the following "empty" `constructor` is generated: @@ -236,16 +236,16 @@ The short answer is: constructors in inheriting classes must call `super(...)`, Of course, there's an explanation. Let's get into details, so you'll really understand what's going on. -In JavaScript, there's a distinction between a "constructor function of an inheriting class" and all others. In an inheriting class, the corresponding constructor function is labeled with a special internal property `[[ConstructorKind]]:"derived"`. +In JavaScript, there's a distinction between a constructor function of an inheriting class (so-called "derived constructor") and other functions. A derived constructor has a special internal property `[[ConstructorKind]]:"derived"`. That's a special internal label. -The difference is: +That label affects its behavior with `new`. -- When a normal constructor runs, it creates an empty object and assigns it to `this`. +- When a regular function is executed with `new`, it creates an empty object and assigns it to `this`. - But when a derived constructor runs, it doesn't do this. It expects the parent constructor to do this job. -So if we're making a constructor of our own, then we must call `super`, because otherwise the object for `this` won't be created. And we'll get an error. +So a derived constructor must call `super` in order to execute its parent (non-derived) constructor, otherwise the object for `this` won't be created. And we'll get an error. -For `Rabbit` constructor to work, it needs to call `super()` before using `this`, like here: +For the `Rabbit` constructor to work, it needs to call `super()` before using `this`, like here: ```js run class Animal { @@ -529,4 +529,4 @@ rabbit.eat(); // Error calling super (because there's no [[HomeObject]]) - So it's not safe to copy a method with `super` from one object to another. Also: -- Arrow functions don't have own `this` or `super`, so they transparently fit into the surrounding context. +- Arrow functions don't have their own `this` or `super`, so they transparently fit into the surrounding context. diff --git a/1-js/09-classes/03-static-properties-methods/article.md b/1-js/09-classes/03-static-properties-methods/article.md index 8e08514f2..fc193e70a 100644 --- a/1-js/09-classes/03-static-properties-methods/article.md +++ b/1-js/09-classes/03-static-properties-methods/article.md @@ -169,7 +169,7 @@ rabbits.sort(Rabbit.compare); rabbits[0].run(); // Black Rabbit runs with speed 5. ``` -Now when we can call `Rabbit.compare`, the inherited `Animal.compare` will be called. +Now when we call `Rabbit.compare`, the inherited `Animal.compare` will be called. How does it work? Again, using prototypes. As you might have already guessed, `extends` gives `Rabbit` the `[[Prototype]]` reference to `Animal`. @@ -180,7 +180,7 @@ So, `Rabbit extends Animal` creates two `[[Prototype]]` references: 1. `Rabbit` function prototypally inherits from `Animal` function. 2. `Rabbit.prototype` prototypally inherits from `Animal.prototype`. -As the result, inheritance works both for regular and static methods. +As a result, inheritance works both for regular and static methods. Here, let's check that by code: @@ -197,7 +197,7 @@ alert(Rabbit.prototype.__proto__ === Animal.prototype); // true ## Summary -Static methods are used for the functionality that belongs to the class "as a whole", doesn't relate to a concrete class instance. +Static methods are used for the functionality that belongs to the class "as a whole". It doesn't relate to a concrete class instance. For example, a method for comparison `Article.compare(article1, article2)` or a factory method `Article.createTodays()`. diff --git a/1-js/09-classes/04-private-protected-properties-methods/article.md b/1-js/09-classes/04-private-protected-properties-methods/article.md index fb1a964c9..6d77e8ed7 100644 --- a/1-js/09-classes/04-private-protected-properties-methods/article.md +++ b/1-js/09-classes/04-private-protected-properties-methods/article.md @@ -50,7 +50,7 @@ That was a general introduction. In JavaScript, there are two types of object fields (properties and methods): -- Public: accessible from anywhere. They comprise the external interface. Till now we were only using public properties and methods. +- Public: accessible from anywhere. They comprise the external interface. Until now we were only using public properties and methods. - Private: accessible only from inside the class. These are for the internal interface. In many other languages there also exist "protected" fields: accessible only from inside the class and those extending it (like private, but plus access from inheriting classes). They are also useful for the internal interface. They are in a sense more widespread than private ones, because we usually want inheriting classes to gain access to them. @@ -257,7 +257,7 @@ class MegaCoffeeMachine extends CoffeeMachine { } ``` -In many scenarios such limitation is too severe. If we extend a `CoffeeMachine`, we may have legitimate reason to access its internals. That's why protected fields are used more often, even though they are not supported by the language syntax. +In many scenarios such limitation is too severe. If we extend a `CoffeeMachine`, we may have legitimate reasons to access its internals. That's why protected fields are used more often, even though they are not supported by the language syntax. ````warn header="Private fields are not available as this[name]" Private fields are special. @@ -283,7 +283,7 @@ In terms of OOP, delimiting of the internal interface from the external one is c It gives the following benefits: -Protection for users, so that they don't shoot themselves in the feet +Protection for users, so that they don't shoot themselves in the foot : Imagine, there's a team of developers using a coffee machine. It was made by the "Best CoffeeMachine" company, and works fine, but a protective cover was removed. So the internal interface is exposed. All developers are civilized -- they use the coffee machine as intended. But one of them, John, decided that he's the smartest one, and made some tweaks in the coffee machine internals. So the coffee machine failed two days later. @@ -308,9 +308,9 @@ Hiding complexity **It's always convenient when implementation details are hidden, and a simple, well-documented external interface is available.** -To hide internal interface we use either protected or private properties: +To hide an internal interface we use either protected or private properties: - Protected fields start with `_`. That's a well-known convention, not enforced at the language level. Programmers should only access a field starting with `_` from its class and classes inheriting from it. -- Private fields start with `#`. JavaScript makes sure we only can access those from inside the class. +- Private fields start with `#`. JavaScript makes sure we can only access those from inside the class. Right now, private fields are not well-supported among browsers, but can be polyfilled. diff --git a/1-js/09-classes/05-extend-natives/article.md b/1-js/09-classes/05-extend-natives/article.md index 9a5686734..28b4c6eb6 100644 --- a/1-js/09-classes/05-extend-natives/article.md +++ b/1-js/09-classes/05-extend-natives/article.md @@ -32,7 +32,7 @@ When `arr.filter()` is called, it internally creates the new array of results us Even more, we can customize that behavior. -We can add a special static getter `Symbol.species` to the class. If exists, it should return the constructor that JavaScript will use internally to create new entities in `map`, `filter` and so on. +We can add a special static getter `Symbol.species` to the class. If it exists, it should return the constructor that JavaScript will use internally to create new entities in `map`, `filter` and so on. If we'd like built-in methods like `map` or `filter` to return regular arrays, we can return `Array` in `Symbol.species`, like here: diff --git a/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md index e9481912a..5b8dc7de3 100644 --- a/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md +++ b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md @@ -4,7 +4,7 @@ importance: 5 # Strange instanceof -Why `instanceof` below returns `true`? We can easily see that `a` is not created by `B()`. +In the code below, why does `instanceof` return `true`? We can easily see that `a` is not created by `B()`. ```js run function A() {} diff --git a/1-js/09-classes/07-mixins/article.md b/1-js/09-classes/07-mixins/article.md index 3be78c627..2ec196105 100644 --- a/1-js/09-classes/07-mixins/article.md +++ b/1-js/09-classes/07-mixins/article.md @@ -101,7 +101,7 @@ Here's the diagram (see the right part): ![](mixin-inheritance.svg) -That's because methods `sayHi` and `sayBye` were initially created in `sayHiMixin`. So even though they got copied, their `[[HomeObject]]` internal property references `sayHiMixin`, as shown on the picture above. +That's because methods `sayHi` and `sayBye` were initially created in `sayHiMixin`. So even though they got copied, their `[[HomeObject]]` internal property references `sayHiMixin`, as shown in the picture above. As `super` looks for parent methods in `[[HomeObject]].[[Prototype]]`, that means it searches `sayHiMixin.[[Prototype]]`, not `User.[[Prototype]]`. @@ -112,7 +112,7 @@ Now let's make a mixin for real life. An important feature of many browser objects (for instance) is that they can generate events. Events are a great way to "broadcast information" to anyone who wants it. So let's make a mixin that allows us to easily add event-related functions to any class/object. - The mixin will provide a method `.trigger(name, [...data])` to "generate an event" when something important happens to it. The `name` argument is a name of the event, optionally followed by additional arguments with event data. -- Also the method `.on(name, handler)` that adds `handler` function as the listener to events with the given name. It will be called when an event with the given `name` triggers, and get the arguments from `.trigger` call. +- Also the method `.on(name, handler)` that adds `handler` function as the listener to events with the given name. It will be called when an event with the given `name` triggers, and get the arguments from the `.trigger` call. - ...And the method `.off(name, handler)` that removes the `handler` listener. After adding the mixin, an object `user` will be able to generate an event `"login"` when the visitor logs in. And another object, say, `calendar` may want to listen for such events to load the calendar for the logged-in person. diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index 0356fa2a8..09b1ee398 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -201,7 +201,7 @@ You can find more detailed information about JSON in the chapter. **If `json` is malformed, `JSON.parse` generates an error, so the script "dies".** -Should we be satisfied with that? Of course, not! +Should we be satisfied with that? Of course not! This way, if something's wrong with the data, the visitor will never know that (unless they open the developer console). And people really don't like when something "just dies" without any error message. @@ -334,9 +334,9 @@ Now `catch` became a single place for all error handling: both for `JSON.parse` ## Rethrowing -In the example above we use `try..catch` to handle incorrect data. But is it possible that *another unexpected error* occurs within the `try {...}` block? Like a programming error (variable is not defined) or something else, not just that "incorrect data" thing. +In the example above we use `try..catch` to handle incorrect data. But is it possible that *another unexpected error* occurs within the `try {...}` block? Like a programming error (variable is not defined) or something else, not just this "incorrect data" thing. -Like this: +For example: ```js run let json = '{ "age": 30 }'; // incomplete data @@ -374,8 +374,8 @@ The rule is simple: The "rethrowing" technique can be explained in more detail as: 1. Catch gets all errors. -2. In `catch(err) {...}` block we analyze the error object `err`. -2. If we don't know how to handle it, then we do `throw err`. +2. In the `catch(err) {...}` block we analyze the error object `err`. +2. If we don't know how to handle it, we do `throw err`. In the code below, we use rethrowing so that `catch` only handles `SyntaxError`: @@ -582,11 +582,11 @@ In the code above, an error inside `try` always falls out, because there's no `c The information from this section is not a part of the core JavaScript. ``` -Let's imagine we've got a fatal error outside of `try..catch`, and the script died. Like a programming error or something else terrible. +Let's imagine we've got a fatal error outside of `try..catch`, and the script died. Like a programming error or some other terrible thing. -Is there a way to react on such occurrences? We may want to log the error, show something to the user (normally they don't see error messages) etc. +Is there a way to react on such occurrences? We may want to log the error, show something to the user (normally they don't see error messages), etc. -There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.js has [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property, that will run in case of an uncaught error. +There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.js has [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to the special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property, that will run in case of an uncaught error. The syntax: diff --git a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md index bb6b74cfa..754e68f9a 100644 --- a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md +++ b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md @@ -2,7 +2,7 @@ class FormatError extends SyntaxError { constructor(message) { super(message); - this.name = "FormatError"; + this.name = this.constructor.name; } } diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md index e5f23a428..b48313322 100644 --- a/1-js/10-error-handling/2-custom-errors/article.md +++ b/1-js/10-error-handling/2-custom-errors/article.md @@ -2,11 +2,11 @@ When we develop something, we often need our own error classes to reflect specific things that may go wrong in our tasks. For errors in network operations we may need `HttpError`, for database operations `DbError`, for searching operations `NotFoundError` and so on. -Our errors should support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have `statusCode` property with a value like `404` or `403` or `500`. +Our errors should support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have a `statusCode` property with a value like `404` or `403` or `500`. JavaScript allows to use `throw` with any argument, so technically our custom error classes don't need to inherit from `Error`. But if we inherit, then it becomes possible to use `obj instanceof Error` to identify error objects. So it's better to inherit from it. -As the application grows, our own errors naturally form a hierarchy, for instance `HttpTimeoutError` may inherit from `HttpError`, and so on. +As the application grows, our own errors naturally form a hierarchy. For instance, `HttpTimeoutError` may inherit from `HttpError`, and so on. ## Extending Error @@ -180,7 +180,7 @@ try { The new class `PropertyRequiredError` is easy to use: we only need to pass the property name: `new PropertyRequiredError(property)`. The human-readable `message` is generated by the constructor. -Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name = ` in every custom error class. We can avoid it by making our own "basic error" class that assigns `this.name = this.constructor.name`. And then inherit all ours custom errors from it. +Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name = ` in every custom error class. We can avoid it by making our own "basic error" class that assigns `this.name = this.constructor.name`. And then inherit all our custom errors from it. Let's call it `MyError`. @@ -291,12 +291,12 @@ try { In the code above, `readUser` works exactly as described -- catches syntax and validation errors and throws `ReadError` errors instead (unknown errors are rethrown as usual). -So the outer code checks `instanceof ReadError` and that's it. No need to list possible all error types. +So the outer code checks `instanceof ReadError` and that's it. No need to list all possible error types. The approach is called "wrapping exceptions", because we take "low level exceptions" and "wrap" them into `ReadError` that is more abstract and more convenient to use for the calling code. It is widely used in object-oriented programming. ## Summary -- We can inherit from `Error` and other built-in error classes normally, just need to take care of `name` property and don't forget to call `super`. -- We can use `instanceof` to check for particular errors. It also works with inheritance. But sometimes we have an error object coming from the 3rd-party library and there's no easy way to get the class. Then `name` property can be used for such checks. +- We can inherit from `Error` and other built-in error classes normally. We just need to take care of the `name` property and don't forget to call `super`. +- We can use `instanceof` to check for particular errors. It also works with inheritance. But sometimes we have an error object coming from a 3rd-party library and there's no easy way to get its class. Then `name` property can be used for such checks. - Wrapping exceptions is a widespread technique: a function handles low-level exceptions and creates higher-level errors instead of various low-level ones. Low-level exceptions sometimes become properties of that object like `err.cause` in the examples above, but that's not strictly required. diff --git a/1-js/99-js-misc/01-proxy/article.md b/1-js/99-js-misc/01-proxy/article.md index b722d0be4..a017a960b 100644 --- a/1-js/99-js-misc/01-proxy/article.md +++ b/1-js/99-js-misc/01-proxy/article.md @@ -603,7 +603,7 @@ Here are examples of operations and `Reflect` calls that do the same: |-----------------|----------------|-------------| | `obj[prop]` | `Reflect.get(obj, prop)` | `[[Get]]` | | `obj[prop] = value` | `Reflect.set(obj, prop, value)` | `[[Set]]` | -| `delete obj[prop]` | `Reflect.deleteProperty(obj, prop)` | `[[HasProperty]]` | +| `delete obj[prop]` | `Reflect.deleteProperty(obj, prop)` | `[[Delete]]` | | `new F(value)` | `Reflect.construct(F, value)` | `[[Construct]]` | | ... | ... | ... | diff --git a/2-ui/1-document/03-dom-navigation/article.md b/2-ui/1-document/03-dom-navigation/article.md index d83d5136d..05ad67079 100644 --- a/2-ui/1-document/03-dom-navigation/article.md +++ b/2-ui/1-document/03-dom-navigation/article.md @@ -226,7 +226,7 @@ The links are similar to those given above, just with `Element` word inside: - `children` -- only those children that are element nodes. - `firstElementChild`, `lastElementChild` -- first and last element children. -- `previousElementSibling`, `nextElementSibling` -- neighbour elements. +- `previousElementSibling`, `nextElementSibling` -- neighbor elements. - `parentElement` -- parent element. ````smart header="Why `parentElement`? Can the parent be *not* an element?" @@ -323,7 +323,7 @@ There are also additional navigation properties for HTML forms. We'll look at th ## Summary -Given a DOM node, we can go to its immediate neighbours using navigation properties. +Given a DOM node, we can go to its immediate neighbors using navigation properties. There are two main sets of them: 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 b802791bb..78bc3fd88 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 @@ -496,4 +496,4 @@ Main DOM node properties are: DOM nodes also have other properties depending on their class. For instance, `` elements (`HTMLInputElement`) support `value`, `type`, while `` elements (`HTMLAnchorElement`) support `href` etc. Most standard HTML attributes have a corresponding DOM property. -Although, HTML attributes and DOM properties are not always the same, as we'll see in the next chapter. +However, HTML attributes and DOM properties are not always the same, as we'll see in the next chapter. diff --git a/2-ui/1-document/07-modifying-document/article.md b/2-ui/1-document/07-modifying-document/article.md index 9cdb79ddd..b624da47c 100644 --- a/2-ui/1-document/07-modifying-document/article.md +++ b/2-ui/1-document/07-modifying-document/article.md @@ -1,12 +1,12 @@ # Modifying the document -DOM modifications is the key to create "live" pages. +DOM modification is the key to creating "live" pages. Here we'll see how to create new elements "on the fly" and modify the existing page content. ## Example: show a message -Let's see the methods on example. We'll add a message on the page that looks nicer than `alert`. +Let's demonstrate using an example. We'll add a message on the page that looks nicer than `alert`. Here's how it will look: @@ -93,9 +93,9 @@ Here's the full code: This set of methods provides more ways to insert: - `node.append(...nodes or strings)` -- append nodes or strings at the end of `node`, -- `node.prepend(...nodes or strings)` -- insert nodes or strings into the beginning of `node`, -- `node.before(...nodes or strings)` –- insert nodes or strings before the `node`, -- `node.after(...nodes or strings)` –- insert nodes or strings after the `node`, +- `node.prepend(...nodes or strings)` -- insert nodes or strings at the beginning of `node`, +- `node.before(...nodes or strings)` –- insert nodes or strings before `node`, +- `node.after(...nodes or strings)` –- insert nodes or strings after `node`, - `node.replaceWith(...nodes or strings)` –- replaces `node` with the given nodes or strings. Here's an example of using these methods to add items to a list and the text before/after it: @@ -199,7 +199,7 @@ For instance:

Bye

``` -That's how we can append an arbitrary HTML to the page. +That's how we can append arbitrary HTML to the page. Here's the picture of insertion variants: @@ -534,13 +534,13 @@ So if we need to add a lot of text into HTML dynamically, and we're at page load All these methods return `node`. -- Given a piece of HTML: `elem.insertAdjacentHTML(where, html)`, inserts depending on `where`: +- Given some HTML in `html`, `elem.insertAdjacentHTML(where, html)` inserts it depending on the value of `where`: - `"beforebegin"` -- insert `html` right before `elem`, - `"afterbegin"` -- insert `html` into `elem`, at the beginning, - `"beforeend"` -- insert `html` into `elem`, at the end, - `"afterend"` -- insert `html` right after `elem`. - Also there are similar methods `elem.insertAdjacentText` and `elem.insertAdjacentElement`, they insert text strings and elements, but they are rarely used. + Also there are also similar methods, `elem.insertAdjacentText` and `elem.insertAdjacentElement`, that insert text strings and elements, but they are rarely used. - To append HTML to the page before it has finished loading: - `document.write(html)` diff --git a/2-ui/2-events/05-dispatch-events/article.md b/2-ui/2-events/05-dispatch-events/article.md index 984e31d90..771f5527b 100644 --- a/2-ui/2-events/05-dispatch-events/article.md +++ b/2-ui/2-events/05-dispatch-events/article.md @@ -207,7 +207,7 @@ Any handler can listen for that event with `rabbit.addEventListener('hide',...)` ``` -Обратите внимание: событие должно иметь флаг `cancelable: true`, иначе вызов `event.preventDefault()` будет проигнорирован. +Please note: the event must have the flag `cancelable: true`, otherwise the call `event.preventDefault()` is ignored. ## Events-in-events are synchronous 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 e7f898f28..ca82a7302 100644 --- a/2-ui/5-loading/02-script-async-defer/article.md +++ b/2-ui/5-loading/02-script-async-defer/article.md @@ -3,11 +3,11 @@ In modern websites, scripts are often "heavier" than HTML: their download size is larger, and processing time is also longer. -When the browser loads HTML and comes across a `` tag, it can't continue building DOM. It must execute the script right now. The same happens for external scripts ``: the browser must wait until the script downloads, execute it, and only after process the rest of the page. +When the browser loads HTML and comes across a `` tag, it can't continue building the DOM. It must execute the script right now. The same happens for external scripts ``: the browser must wait until the script downloads, execute it, and only after process the rest of the page. That leads to two important issues: -1. Scripts can't see DOM elements below them, so can't add handlers etc. +1. Scripts can't see DOM elements below them, so they can't add handlers etc. 2. If there's a bulky script at the top of the page, it "blocks the page". Users can't see the page content till it downloads and runs: ```html run height=100 @@ -31,7 +31,7 @@ There are some workarounds to that. For instance, we can put a script at the bot But this solution is far from perfect. For example, the browser notices the script (and can start downloading it) only after it downloaded the full HTML document. For long HTML documents, that may be a noticeable delay. -Such things are invisible for people using very fast connections, but many people in the world still have slower internet speeds and use far-from-perfect mobile internet. +Such things are invisible for people using very fast connections, but many people in the world still have slow internet speeds and use a far-from-perfect mobile internet connection. Luckily, there are two `