Skip to content

Commit 63cbf4a

Browse files
authored
Merge pull request #188 from javascript-tutorial/sync-d6e88647
Sync with upstream @ d6e8864
2 parents 3bc567d + 28e6849 commit 63cbf4a

File tree

5 files changed

+86
-95
lines changed
  • 1-js
    • 04-object-basics/07-optional-chaining
    • 05-data-types/05-array-methods/2-filter-range
  • 2-ui
  • 9-regular-expressions/16-regexp-sticky

5 files changed

+86
-95
lines changed

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

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,51 +9,81 @@ 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, 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.
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.
1313

14-
In such case, when we attempt to get `user.address.street`, we'll get an error:
14+
In such case, when we attempt to get `user.address.street`, we may get an error:
1515

1616
```js run
17-
let user = {}; // the user without "address" property
17+
let user = {}; // a user without "address" property
1818

1919
alert(user.address.street); // Error!
2020
```
2121

22-
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").
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").
2323

24-
...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:
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:
2525

2626
```js run
27-
// Error if the result of querySelector(...) is null
28-
let html = document.querySelector('.my-element').innerHTML;
27+
// the result of the call document.querySelector('.elem') may be an object or null
28+
let html = document.querySelector('.elem').innerHTML; // error if it's null
2929
```
3030

31-
Before `?.` appeared in the language, the `&&` operator was used to work around that.
31+
Once again, we may want to avoid the error in such case.
3232

33-
For example:
33+
How can we do this?
34+
35+
The obvious solution would be to check the value using `if` or the conditional operator `?`, before accessing it, like this:
36+
37+
```js
38+
let user = {};
39+
40+
alert(user.address ? user.address.street : undefined);
41+
```
42+
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.
44+
45+
E.g. let's try getting `user.address.street.name`.
46+
47+
We need to check both `user.address` and `user.address.street`:
48+
49+
```js
50+
let user = {}; // user has no address
51+
52+
alert(user.address ? user.address.street ? user.address.street.name : null : null);
53+
```
54+
55+
That looks awful.
56+
57+
Before the optional chaining `?.` was added to the language, people used the `&&` operator for such cases:
3458

3559
```js run
3660
let user = {}; // user has no address
3761

38-
alert( user && user.address && user.address.street ); // undefined (no error)
62+
alert( user.address && user.address.street && user.address.street.name ); // undefined (no error)
3963
```
4064

41-
AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but is cumbersome to write.
65+
AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but also isn't ideal.
66+
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.
68+
69+
And now, finally, the optional chaining comes to the rescue!
4270

4371
## Optional chaining
4472

4573
The optional chaining `?.` stops the evaluation and returns `undefined` if the part before `?.` is `undefined` or `null`.
4674

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

49-
Here's the safe way to access `user.address.street`:
77+
Here's the safe way to access `user.address.street` using `?.`:
5078

5179
```js run
5280
let user = {}; // user has no address
5381

5482
alert( user?.address?.street ); // undefined (no error)
5583
```
5684
85+
The code is short and clean, there's no duplication at all.
86+
5787
Reading the address with `user?.address` works even if `user` object doesn't exist:
5888
5989
```js run
@@ -65,14 +95,14 @@ alert( user?.address.street ); // undefined
6595
6696
Please note: the `?.` syntax makes optional the value before it, but not any further.
6797
68-
In the example above, `user?.` allows only `user` to be `null/undefined`.
98+
In the example above, `user?.address.street` allows only `user` to be `null/undefined`.
6999
70100
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.
71101
72102
```warn header="Don't overuse the optional chaining"
73103
We should use `?.` only where it's ok that something doesn't exist.
74104

75-
For example, if according to our coding logic `user` object must be there, but `address` is optional, then `user.address?.street` would be better.
105+
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`.
76106

77107
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.
78108
```
@@ -84,7 +114,7 @@ If there's no variable `user` at all, then `user?.anything` triggers an error:
84114
// ReferenceError: user is not defined
85115
user?.address;
86116
```
87-
There must be a declaration (e.g. `let/const/var user`). The optional chaining works only for declared variables.
117+
The variable must be declared (e.g. `let/const/var user` or as a function parameter). The optional chaining works only for declared variables.
88118
````
89119

90120
## Short-circuiting

1-js/05-data-types/05-array-methods/2-filter-range/task.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ importance: 4
44

55
# Filter range
66

7-
Write a function `filterRange(arr, a, b)` that gets an array `arr`, looks for elements between `a` and `b` in it and returns an array of them.
7+
Write a function `filterRange(arr, a, b)` that gets an array `arr`, looks for elements with values higher or equal to `a` and lower or equal to `b` and return a result as an array.
88

99
The function should not modify the array. It should return the new array.
1010

2-ui/1-document/05-basic-dom-node-properties/article.md

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,8 @@ The classes are:
2020

2121
- [EventTarget](https://dom.spec.whatwg.org/#eventtarget) -- is the root "abstract" class. Objects of that class are never created. It serves as a base, so that all DOM nodes support so-called "events", we'll study them later.
2222
- [Node](http://dom.spec.whatwg.org/#interface-node) -- is also an "abstract" class, serving as a base for DOM nodes. It provides the core tree functionality: `parentNode`, `nextSibling`, `childNodes` and so on (they are getters). Objects of `Node` class are never created. But there are concrete node classes that inherit from it, namely: `Text` for text nodes, `Element` for element nodes and more exotic ones like `Comment` for comment nodes.
23-
<<<<<<< HEAD
24-
- [Element](http://dom.spec.whatwg.org/#interface-element) -- is a base class for DOM elements. It provides element-level navigation like `nextElementSibling`, `children` and searching methods like `getElementsByTagName`, `querySelector`. In the browser there may be not only HTML, but also XML and SVG documents. The `Element` class serves as a base for more specific classes: `SVGElement`, `XMLElement` and `HTMLElement`.
25-
- [HTMLElement](https://html.spec.whatwg.org/multipage/dom.html#htmlelement) -- is finally the basic class for all HTML elements. It is inherited by various HTML elements:
26-
=======
2723
- [Element](http://dom.spec.whatwg.org/#interface-element) -- is a base class for DOM elements. It provides element-level navigation like `nextElementSibling`, `children` and searching methods like `getElementsByTagName`, `querySelector`. A browser supports not only HTML, but also XML and SVG. The `Element` class serves as a base for more specific classes: `SVGElement`, `XMLElement` and `HTMLElement`.
2824
- [HTMLElement](https://html.spec.whatwg.org/multipage/dom.html#htmlelement) -- is finally the basic class for all HTML elements. It is inherited by concrete HTML elements:
29-
>>>>>>> e074a5f825a3d10b0c1e5e82561162f75516d7e3
3025
- [HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement) -- the class for `<input>` elements,
3126
- [HTMLBodyElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlbodyelement) -- the class for `<body>` elements,
3227
- [HTMLAnchorElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlanchorelement) -- the class for `<a>` elements
@@ -36,19 +31,12 @@ So, the full set of properties and methods of a given node comes as the result o
3631

3732
For example, let's consider the DOM object for an `<input>` element. It belongs to [HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement) class. It gets properties and methods as a superposition of:
3833

39-
<<<<<<< HEAD
40-
- `HTMLInputElement` -- this class provides input-specific properties, and inherits from...
41-
- `HTMLElement` -- it provides common HTML element methods (and getters/setters) and inherits from...
42-
- `Element` -- provides generic element methods and inherits from...
43-
- `Node` -- provides common DOM node properties and inherits from...
44-
=======
4534
It gets properties and methods as a superposition of (listed in inheritance order):
4635

4736
- `HTMLInputElement` -- this class provides input-specific properties,
4837
- `HTMLElement` -- it provides common HTML element methods (and getters/setters),
4938
- `Element` -- provides generic element methods,
5039
- `Node` -- provides common DOM node properties,
51-
>>>>>>> e074a5f825a3d10b0c1e5e82561162f75516d7e3
5240
- `EventTarget` -- gives the support for events (to be covered),
5341
- ...and finally it inherits from `Object`, so "pure object" methods like `hasOwnProperty` are also available.
5442

@@ -325,13 +313,6 @@ Consider the example:
325313
</script>
326314
```
327315
328-
<<<<<<< HEAD
329-
In the line `(*)` we take the full HTML of `<div>...</div>` and replace it by `<p>...</p>`. In the outer document we can see the new content instead of the `<div>`. But the old `div` variable is still the same.
330-
331-
The `outerHTML` assignment does not modify the DOM element, but extracts it from the outer context and inserts a new piece of HTML instead of it.
332-
333-
Novice developers sometimes make an error here: they modify `div.outerHTML` and then continue to work with `div` as if it had the new content in it.
334-
=======
335316
Looks really odd, right?
336317
337318
In the line `(*)` we replaced `div` with `<p>A new element</p>`. In the outer document (the DOM) we can see the new content instead of the `<div>`. But, as we can see in line `(**)`, the value of the old `div` variable hasn't changed!
@@ -342,15 +323,10 @@ So what happened in `div.outerHTML=...` is:
342323
- `div` was removed from the document.
343324
- Another piece of HTML `<p>A new element</p>` was inserted in its place.
344325
- `div` still has its old value. The new HTML wasn't saved to any variable.
345-
>>>>>>> e074a5f825a3d10b0c1e5e82561162f75516d7e3
346326
347327
That's possible with `innerHTML`, but not with `outerHTML`.
348328
349-
<<<<<<< HEAD
350-
We can write to `outerHTML`, but should keep in mind that it doesn't change the element we're writing to. It creates the new content on its place instead. We can get a reference to new elements by querying DOM.
351-
=======
352329
We can write to `elem.outerHTML`, but should keep in mind that it doesn't change the element we're writing to ('elem'). It puts the new HTML in its place instead. We can get references to the new elements by querying the DOM.
353-
>>>>>>> e074a5f825a3d10b0c1e5e82561162f75516d7e3
354330
355331
## nodeValue/data: text node content
356332
@@ -424,23 +400,23 @@ Compare the two:
424400
<div id="elem2"></div>
425401
426402
<script>
427-
let name = prompt("What's your name?", "<b>Winnie-the-pooh!</b>");
403+
let name = prompt("What's your name?", "<b>Winnie-the-Pooh!</b>");
428404
429405
elem1.innerHTML = name;
430406
elem2.textContent = name;
431407
</script>
432408
```
433409
434410
1. The first `<div>` gets the name "as HTML": all tags become tags, so we see the bold name.
435-
2. The second `<div>` gets the name "as text", so we literally see `<b>Winnie-the-pooh!</b>`.
411+
2. The second `<div>` gets the name "as text", so we literally see `<b>Winnie-the-Pooh!</b>`.
436412
437413
In most cases, we expect the text from a user, and want to treat it as text. We don't want unexpected HTML in our site. An assignment to `textContent` does exactly that.
438414
439415
## The "hidden" property
440416
441417
The "hidden" attribute and the DOM property specifies whether the element is visible or not.
442418
443-
We can use it in HTML or assign using JavaScript, like this:
419+
We can use it in HTML or assign it using JavaScript, like this:
444420
445421
```html run height="80"
446422
<div>Both divs below are hidden</div>
@@ -501,11 +477,7 @@ Each DOM node belongs to a certain class. The classes form a hierarchy. The full
501477
Main DOM node properties are:
502478
503479
`nodeType`
504-
<<<<<<< HEAD
505-
: We can get `nodeType` from the DOM object class, but often we need just to see if it is a text or element node. The `nodeType` property is good for that. It has numeric values, most important are: `1` -- for elements,`3` -- for text nodes. Read-only.
506-
=======
507480
: We can use it to see if a node is a text or an element node. It has a numeric value: `1` for elements,`3` for text nodes, and a few others for other node types. Read-only.
508-
>>>>>>> e074a5f825a3d10b0c1e5e82561162f75516d7e3
509481
510482
`nodeName/tagName`
511483
: For elements, tag name (uppercased unless XML-mode). For non-element nodes `nodeName` describes what it is. Read-only.
@@ -527,8 +499,4 @@ Main DOM node properties are:
527499
528500
DOM nodes also have other properties depending on their class. For instance, `<input>` elements (`HTMLInputElement`) support `value`, `type`, while `<a>` elements (`HTMLAnchorElement`) support `href` etc. Most standard HTML attributes have a corresponding DOM property.
529501
530-
<<<<<<< HEAD
531-
But HTML attributes and DOM properties are not always the same, as we'll see in the next chapter.
532-
=======
533502
However, HTML attributes and DOM properties are not always the same, as we'll see in the next chapter.
534-
>>>>>>> e074a5f825a3d10b0c1e5e82561162f75516d7e3

2-ui/4-forms-controls/1-form-elements/article.md

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -167,28 +167,18 @@ input.checked = true; // for a checkbox or radio button
167167
```
168168
169169
```warn header="Use `textarea.value`, not `textarea.innerHTML`"
170-
<<<<<<< HEAD
171-
Please note that we should never use `textarea.innerHTML`: it stores only the HTML that was initially on the page, not the current value.
172-
=======
173170
Please note that even though `<textarea>...</textarea>` holds its value as nested HTML, we should never use `textarea.innerHTML` to access it.
174171
175172
It stores only the HTML that was initially on the page, not the current value.
176-
>>>>>>> e074a5f825a3d10b0c1e5e82561162f75516d7e3
177173
```
178174
179175
### select and option
180176
181177
A `<select>` element has 3 important properties:
182178
183-
<<<<<<< HEAD
184-
1. `select.options` -- the collection of `<option>` elements,
185-
2. `select.value` -- the value of the chosen option,
186-
3. `select.selectedIndex` -- the number of the selected option.
187-
=======
188179
1. `select.options` -- the collection of `<option>` subelements,
189180
2. `select.value` -- the value of the currently selected `<option>`,
190181
3. `select.selectedIndex` -- the number of the currently selected `<option>`.
191-
>>>>>>> e074a5f825a3d10b0c1e5e82561162f75516d7e3
192182
193183
They provide three different ways of setting a value for a `<select>`:
194184
@@ -215,7 +205,9 @@ Here is an example:
215205
</script>
216206
```
217207
218-
Unlike most other controls, `<select>` allows to select multiple options at once if it has `multiple` attribute. That's feature is rarely used. In that case we need to use the first way: add/remove the `selected` property from `<option>` subelements.
208+
Unlike most other controls, `<select>` allows to select multiple options at once if it has `multiple` attribute. Although such functionality is available, it is rarely used.
209+
210+
In cases that you have to, then use the first way: add/remove the `selected` property from `<option>` subelements.
219211
220212
We can get their collection as `select.options`, for instance:
221213
@@ -240,13 +232,9 @@ The full specification of the `<select>` element is available at <https://html.s
240232
241233
### new Option
242234
243-
<<<<<<< HEAD
244-
In the specification of [the option element](https://html.spec.whatwg.org/multipage/forms.html#the-option-element) there's a nice short syntax to create `<option>` elements:
245-
=======
246235
This is rarely used on its own. But there's still an interesting thing.
247236
248237
In the [specification](https://html.spec.whatwg.org/multipage/forms.html#the-option-element) there's a nice short syntax to create `<option>` elements:
249-
>>>>>>> e074a5f825a3d10b0c1e5e82561162f75516d7e3
250238
251239
```js
252240
option = new Option(text, value, defaultSelected, selected);
@@ -304,14 +292,8 @@ Form navigation:
304292
305293
Value is available as `input.value`, `textarea.value`, `select.value` etc, or `input.checked` for checkboxes and radio buttons.
306294
307-
<<<<<<< HEAD
308-
For `<select>` we can also get the value by the index `select.selectedIndex` or through the options collection `select.options`. The full specification of this and other elements is at <https://html.spec.whatwg.org/multipage/forms.html>.
309-
310-
These are the basics to start working with forms. In the next chapter we'll cover `focus` and `blur` events that may occur on any element, but are mostly handled on forms.
311-
=======
312295
For `<select>` we can also get the value by the index `select.selectedIndex` or through the options collection `select.options`.
313296
314297
These are the basics to start working with forms. We'll meet many examples further in the tutorial.
315298
316299
In the next chapter we'll cover `focus` and `blur` events that may occur on any element, but are mostly handled on forms.
317-
>>>>>>> e074a5f825a3d10b0c1e5e82561162f75516d7e3

0 commit comments

Comments
 (0)