Skip to content

Commit 5c102c0

Browse files
committed
Merge branch 'master' of github.com:javascript-tutorial/en.javascript.info into sync-2d5be7b7
2 parents de0ce47 + 2d5be7b commit 5c102c0

File tree

9 files changed

+44
-33
lines changed

9 files changed

+44
-33
lines changed

1-js/04-object-basics/07-optional-chaining/article.md

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,38 +9,42 @@ The optional chaining `?.` is a safe way to access nested object properties, eve
99

1010
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.
1111

12-
As an example, 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.
12+
As an example, let's say we have `user` objects that hold the information about our users.
1313

14-
In such case, when we attempt to get `user.address.street`, we may get an error:
14+
Most of our users have addresses in `user.address` property, with the street `user.address.street`, but some did not provide them.
15+
16+
In such case, when we attempt to get `user.address.street`, and the user happens to be without an address, we get an error:
1517

1618
```js run
1719
let user = {}; // a user without "address" property
1820

1921
alert(user.address.street); // Error!
2022
```
2123

22-
That's the expected result, JavaScript works like this. As `user.address` is `undefined`, the attempt to get `user.address.street` fails with an error. Although, in many practical cases we'd prefer to get `undefined` instead of an error here (meaning "no street").
24+
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.
25+
26+
In many practical cases we'd prefer to get `undefined` instead of an error here (meaning "no street").
2327

24-
...And another example. In the web development, we may need the information about an element on the page. The element is returned by `document.querySelector('.elem')`, and the catch is again - that it sometimes doesn't exist:
28+
...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.
2529

2630
```js run
27-
// the result of the call document.querySelector('.elem') may be an object or null
31+
// document.querySelector('.elem') is null if there's no element
2832
let html = document.querySelector('.elem').innerHTML; // error if it's null
2933
```
3034

31-
Once again, we may want to avoid the error in such case.
35+
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.
3236

3337
How can we do this?
3438

35-
The obvious solution would be to check the value using `if` or the conditional operator `?`, before accessing it, like this:
39+
The obvious solution would be to check the value using `if` or the conditional operator `?`, before accessing its property, like this:
3640

3741
```js
3842
let user = {};
3943

4044
alert(user.address ? user.address.street : undefined);
4145
```
4246

43-
...But that's quite inelegant. As you can see, the `user.address` is duplicated in the code. For more deeply nested properties, that becomes a problem.
47+
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.
4448

4549
E.g. let's try getting `user.address.street.name`.
4650

@@ -52,9 +56,9 @@ let user = {}; // user has no address
5256
alert(user.address ? user.address.street ? user.address.street.name : null : null);
5357
```
5458

55-
That looks awful.
59+
That's just awful, one may even have problems understanding such code.
5660

57-
Before the optional chaining `?.` was added to the language, people used the `&&` operator for such cases:
61+
Don't even care to, as there's a better way to write it, using the `&&` operator:
5862

5963
```js run
6064
let user = {}; // user has no address
@@ -64,16 +68,20 @@ alert( user.address && user.address.street && user.address.street.name ); // und
6468

6569
AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but also isn't ideal.
6670

67-
As you can see, the property names are still duplicated in the code. E.g. in the code above, `user.address` appears three times.
71+
As you can see, property names are still duplicated in the code. E.g. in the code above, `user.address` appears three times.
6872

69-
And now, finally, the optional chaining comes to the rescue!
73+
That's why the optional chaining `?.` was added to the language. To solve this problem once and for all!
7074

7175
## Optional chaining
7276

73-
The optional chaining `?.` stops the evaluation and returns `undefined` if the part before `?.` is `undefined` or `null`.
77+
The optional chaining `?.` stops the evaluation if the part before `?.` is `undefined` or `null` and returns that part.
7478

7579
**Further in this article, for brevity, we'll be saying that something "exists" if it's not `null` and not `undefined`.**
7680

81+
In other words, `value?.prop`:
82+
- is the same as `value.prop` if `value` exists,
83+
- otherwise (when `value` is `undefined/null`) it returns that `value`.
84+
7785
Here's the safe way to access `user.address.street` using `?.`:
7886

7987
```js run
@@ -95,9 +103,7 @@ alert( user?.address.street ); // undefined
95103
96104
Please note: the `?.` syntax makes optional the value before it, but not any further.
97105
98-
In the example above, `user?.address.street` allows only `user` to be `null/undefined`.
99-
100-
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.
106+
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 `?.`.
101107
102108
```warn header="Don't overuse the optional chaining"
103109
We should use `?.` only where it's ok that something doesn't exist.
@@ -143,17 +149,20 @@ For example, `?.()` is used to call a function that may not exist.
143149
In the code below, some of our users have `admin` method, and some don't:
144150

145151
```js run
146-
let user1 = {
152+
let userAdmin = {
147153
admin() {
148154
alert("I am admin");
149155
}
150-
}
156+
};
157+
158+
let userGuest = {};
151159

152-
let user2 = {};
160+
*!*
161+
userAdmin.admin?.(); // I am admin
162+
*/!*
153163

154164
*!*
155-
user1.admin?.(); // I am admin
156-
user2.admin?.();
165+
userGuest.admin?.(); // nothing (no such method)
157166
*/!*
158167
```
159168

1-js/06-advanced-functions/04-var/article.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ function sayHi() {
8282
}
8383

8484
sayHi();
85-
alert(phrase); // Error: phrase is not defined (Check the Developer Console)
85+
alert(phrase); // Error: phrase is not defined
8686
```
8787

8888
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.
279279

280280
There are two main differences of `var` compared to `let/const`:
281281

282-
1. `var` variables have no block scope; their visibility is scoped to current function, or global, if declared outside function.
282+
1. `var` variables have no block scope, their visibility is scoped to current function, or global, if declared outside function.
283283
2. `var` declarations are processed at function start (script start for globals).
284284

285285
There's one more very minor difference related to the global object, that we'll cover in the next chapter.

1-js/06-advanced-functions/05-global-object/article.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ The global object provides variables and functions that are available anywhere.
55

66
In a browser it is named `window`, for Node.js it is `global`, for other environments it may have another name.
77

8-
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.
8+
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.
99

1010
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.
1111

@@ -25,6 +25,8 @@ var gVar = 5;
2525
alert(window.gVar); // 5 (became a property of the global object)
2626
```
2727

28+
The same effect have function declarations (statements with `function` keyword in the main code flow, not function expressions).
29+
2830
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.
2931

3032
If we used `let` instead, such thing wouldn't happen:

1-js/06-advanced-functions/06-function-object/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ If the function is declared as a Function Expression (not in the main code flow)
347347

348348
Also, functions may carry additional properties. Many well-known JavaScript libraries make great use of this feature.
349349

350-
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.
350+
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.
351351

352352

353353
So, a function can do a useful job by itself and also carry a bunch of other functionality in properties.

1-js/06-advanced-functions/07-new-function/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ What if it could access the outer variables?
9292

9393
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.
9494

95-
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.
95+
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.
9696

9797
So if `new Function` had access to outer variables, it would be unable to find renamed `userName`.
9898

1-js/06-advanced-functions/08-settimeout-setinterval/article.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ setTimeout(() => { clearInterval(timerId); alert('stop'); }, 5000);
129129
```smart header="Time goes on while `alert` is shown"
130130
In most browsers, including Chrome and Firefox the internal timer continues "ticking" while showing `alert/confirm/prompt`.
131131

132-
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.
132+
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.
133133
```
134134
135135
## Nested setTimeout
@@ -281,7 +281,7 @@ The similar thing happens if we use `setInterval` instead of `setTimeout`: `setI
281281
282282
That limitation comes from ancient times and many scripts rely on it, so it exists for historical reasons.
283283
284-
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.
284+
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.
285285
````
286286

287287
## Summary
@@ -290,7 +290,7 @@ For server-side JavaScript, that limitation does not exist, and there exist othe
290290
- To cancel the execution, we should call `clearTimeout/clearInterval` with the value returned by `setTimeout/setInterval`.
291291
- Nested `setTimeout` calls are a more flexible alternative to `setInterval`, allowing us to set the time *between* executions more precisely.
292292
- 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".
293-
- 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.
293+
- 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.
294294

295295
Please note that all scheduling methods do not *guarantee* the exact delay.
296296

1-js/08-prototypes/01-prototype-inheritance/article.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,8 @@ alert(admin.fullName); // John Smith (*)
198198
// setter triggers!
199199
admin.fullName = "Alice Cooper"; // (**)
200200

201-
alert(admin.fullName); // Alice Cooper , state of admin modified
202-
alert(user.fullName); // John Smith , state of user protected
201+
alert(admin.fullName); // Alice Cooper, state of admin modified
202+
alert(user.fullName); // John Smith, state of user protected
203203
```
204204

205205
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.

2-ui/2-events/02-bubbling-and-capturing/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ When an event happens -- the most nested element where it happens gets labeled a
206206
207207
- 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}`).
208208
- Then handlers are called on the target element itself.
209-
- Then the event bubbles up from `event.target` to the root, calling handlers assigned using `on<event>` and `addEventListener` without the 3rd argument or with the 3rd argument `false/{capture:false}`.
209+
- Then the event bubbles up from `event.target` to the root, calling handlers assigned using `on<event>`, HTML attributes and `addEventListener` without the 3rd argument or with the 3rd argument `false/{capture:false}`.
210210
211211
Each handler can access `event` object properties:
212212

2-ui/2-events/03-event-delegation/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Capturing and bubbling allow us to implement one of most powerful event handling
55

66
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.
77

8-
In the handler we get `event.target`, see where the event actually happened and handle it.
8+
In the handler we get `event.target` to see where the event actually happened and handle it.
99

1010
Let's see an example -- the [Ba-Gua diagram](http://en.wikipedia.org/wiki/Ba_gua) reflecting the ancient Chinese philosophy.
1111

0 commit comments

Comments
 (0)