Skip to content

Commit 246c6c4

Browse files
authored
Merge branch 'master' into patch-1
2 parents 689392e + ac92672 commit 246c6c4

File tree

54 files changed

+283
-201
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+283
-201
lines changed

1-js/01-getting-started/1-intro/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ Examples of such restrictions include:
6868
Modern browsers allow it to work with files, but the access is limited and only provided if the user does certain actions, like "dropping" a file into a browser window or selecting it via an `<input>` tag.
6969

7070
There are ways to interact with camera/microphone and other devices, but they require a user's explicit permission. So a JavaScript-enabled page may not sneakily enable a web-camera, observe the surroundings and send the information to the [NSA](https://en.wikipedia.org/wiki/National_Security_Agency).
71-
- Different tabs/windows generally do not know about each other. Sometimes they do; for example when one window uses JavaScript to open the other one. But even in this case, JavaScript from one page may not access the other if they come from different sites (from a different domain, protocol or port).
71+
- Different tabs/windows generally do not know about each other. Sometimes they do, for example when one window uses JavaScript to open the other one. But even in this case, JavaScript from one page may not access the other if they come from different sites (from a different domain, protocol or port).
7272

7373
This is called the "Same Origin Policy". To work around that, *both pages* must agree for data exchange and contain a special JavaScript code that handles it. We'll cover that in the tutorial.
7474

1-js/01-getting-started/4-devtools/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ To see errors and get a lot of other useful information about scripts, "develope
88

99
Most developers lean towards Chrome or Firefox for development because those browsers have the best developer tools. Other browsers also provide developer tools, sometimes with special features, but are usually playing "catch-up" to Chrome or Firefox. So most developers have a "favorite" browser and switch to others if a problem is browser-specific.
1010

11-
Developer tools are potent; they have many features. To start, we'll learn how to open them, look at errors, and run JavaScript commands.
11+
Developer tools are potent, they have many features. To start, we'll learn how to open them, look at errors, and run JavaScript commands.
1212

1313
## Google Chrome
1414

1-js/02-first-steps/01-hello-world/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ So first, let's see how we attach a script to a webpage. For server-side environ
99

1010
## The "script" tag
1111

12-
JavaScript programs can be inserted into any part of an HTML document with the help of the `<script>` tag.
12+
JavaScript programs can be inserted almost anywhere into an HTML document using the `<script>` tag.
1313

1414
For instance:
1515

1-js/03-code-quality/02-coding-style/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ Here's an example of an `.eslintrc` file:
328328
},
329329
"rules": {
330330
"no-console": 0,
331-
"indent": ["warning", 2]
331+
"indent": 2
332332
}
333333
}
334334
```

1-js/03-code-quality/06-polyfills/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Actually, there are two parts in Babel:
2323

2424
2. Second, the polyfill.
2525

26-
New language features may include new built-in functions and syntax constructs.
26+
New language features may include not only syntax constructs, but also built-in functions.
2727
The transpiler rewrites the code, transforming syntax constructs into older ones. But as for new built-in functions, we need to implement them. JavaScript is a highly dynamic language, scripts may add/modify any functions, so that they behave according to the modern standard.
2828

2929
A script that updates/adds new functions is called "polyfill". It "fills in" the gap and adds missing implementations.

1-js/04-object-basics/01-object/article.md

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -92,30 +92,6 @@ let user = {
9292
```
9393
That is called a "trailing" or "hanging" comma. Makes it easier to add/remove/move around properties, because all lines become alike.
9494

95-
````smart header="Object with const can be changed"
96-
Please note: an object declared as `const` *can* be modified.
97-
98-
For instance:
99-
100-
```js run
101-
const user = {
102-
name: "John"
103-
};
104-
105-
*!*
106-
user.name = "Pete"; // (*)
107-
*/!*
108-
109-
alert(user.name); // Pete
110-
```
111-
112-
It might seem that the line `(*)` would cause an error, but no. The `const` fixes the value of `user`, but not its contents.
113-
114-
The `const` would give an error only if we try to set `user=...` as a whole.
115-
116-
There's another way to make constant object properties, we'll cover it later in the chapter <info:property-descriptors>.
117-
````
118-
11995
## Square brackets
12096

12197
For multiword properties, the dot access doesn't work:

1-js/04-object-basics/02-object-copy/article.md

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Object references and copying
22

3-
One of the fundamental differences of objects versus primitives is that objects are stored and copied "by reference", as opposed to primitive values: strings, numbers, booleans, etc -- that are always copied "as a whole value".
3+
One of the fundamental differences of objects versus primitives is that objects are stored and copied "by reference", whereas primitive values: strings, numbers, booleans, etc -- are always copied "as a whole value".
44

5-
That's easy to understand if we look a bit "under a cover" of what happens when we copy a value.
5+
That's easy to understand if we look a bit under the hood of what happens when we copy a value.
66

77
Let's start with a primitive, such as a string.
88

@@ -13,17 +13,17 @@ let message = "Hello!";
1313
let phrase = message;
1414
```
1515

16-
As a result we have two independent variables, each one is storing the string `"Hello!"`.
16+
As a result we have two independent variables, each one storing the string `"Hello!"`.
1717

1818
![](variable-copy-value.svg)
1919

2020
Quite an obvious result, right?
2121

2222
Objects are not like that.
2323

24-
**A variable assigned to an object stores not the object itself, but its "address in memory", in other words "a reference" to it.**
24+
**A variable assigned to an object stores not the object itself, but its "address in memory" -- in other words "a reference" to it.**
2525

26-
Let's look at an example of such variable:
26+
Let's look at an example of such a variable:
2727

2828
```js
2929
let user = {
@@ -37,13 +37,13 @@ And here's how it's actually stored in memory:
3737

3838
The object is stored somewhere in memory (at the right of the picture), while the `user` variable (at the left) has a "reference" to it.
3939

40-
We may think of an object variable, such as `user`, as of a sheet of paper with the address.
40+
We may think of an object variable, such as `user`, as like a sheet of paper with the address of the object on it.
4141

42-
When we perform actions with the object, e.g. take a property `user.name`, JavaScript engine looks into that address and performs the operation on the actual object.
42+
When we perform actions with the object, e.g. take a property `user.name`, the JavaScript engine looks at what's at that address and performs the operation on the actual object.
4343

4444
Now here's why it's important.
4545

46-
**When an object variable is copied -- the reference is copied, the object is not duplicated.**
46+
**When an object variable is copied, the reference is copied, but the object itself is not duplicated.**
4747

4848
For instance:
4949

@@ -53,13 +53,13 @@ let user = { name: "John" };
5353
let admin = user; // copy the reference
5454
```
5555

56-
Now we have two variables, each one with the reference to the same object:
56+
Now we have two variables, each storing a reference to the same object:
5757

5858
![](variable-copy-reference.svg)
5959

60-
As you can see, there's still one object, now with two variables that reference it.
60+
As you can see, there's still one object, but now with two variables that reference it.
6161

62-
We can use any variable to access the object and modify its contents:
62+
We can use either variable to access the object and modify its contents:
6363

6464
```js run
6565
let user = { name: 'John' };
@@ -73,8 +73,7 @@ admin.name = 'Pete'; // changed by the "admin" reference
7373
alert(*!*user.name*/!*); // 'Pete', changes are seen from the "user" reference
7474
```
7575
76-
77-
It's just as if we had a cabinet with two keys and used one of them (`admin`) to get into it. Then, if we later use another key (`user`) we can see changes.
76+
It's as if we had a cabinet with two keys and used one of them (`admin`) to get into it and make changes. Then, if we later use another key (`user`), we are still opening the same cabinet and can access the changed contents.
7877
7978
## Comparison by reference
8079
@@ -99,15 +98,15 @@ let b = {}; // two independent objects
9998
alert( a == b ); // false
10099
```
101100
102-
For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons are needed very rarely, usually they appear as a result of a programming mistake.
101+
For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons are needed very rarely -- usually they appear as a result of a programming mistake.
103102
104103
## Cloning and merging, Object.assign
105104
106105
So, copying an object variable creates one more reference to the same object.
107106
108107
But what if we need to duplicate an object? Create an independent copy, a clone?
109108
110-
That's also doable, but a little bit more difficult, because there's no built-in method for that in JavaScript. Actually, that's rarely needed. Copying by reference is good most of the time.
109+
That's also doable, but a little bit more difficult, because there's no built-in method for that in JavaScript. But there is rarely a need -- copying by reference is good most of the time.
111110
112111
But if we really want that, then we need to create a new object and replicate the structure of the existing one by iterating over its properties and copying them on the primitive level.
113112
@@ -226,13 +225,37 @@ user.sizes.width++; // change a property from one place
226225
alert(clone.sizes.width); // 51, see the result from the other one
227226
```
228227
229-
To fix that, we should use the cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning".
228+
To fix that, we should use a cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning".
229+
230+
We can use recursion to implement it. Or, to not reinvent the wheel, take an existing implementation, for instance [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) from the JavaScript library [lodash](https://lodash.com).
231+
232+
````smart header="Const objects can be modified"
233+
An important side effect of storing objects as references is that an object declared as `const` *can* be modified.
234+
235+
For instance:
236+
237+
```js run
238+
const user = {
239+
name: "John"
240+
};
241+
242+
*!*
243+
user.name = "Pete"; // (*)
244+
*/!*
245+
246+
alert(user.name); // Pete
247+
```
248+
249+
It might seem that the line `(*)` would cause an error, but it does not. The value of `user` is constant, it must always reference the same object, but properties of that object are free to change.
250+
251+
In other words, the `const user` gives an error only if we try to set `user=...` as a whole.
230252

231-
We can use recursion to implement it. Or, not to reinvent the wheel, take an existing implementation, for instance [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) from the JavaScript library [lodash](https://lodash.com).
253+
That said, if we really need to make constant object properties, it's also possible, but using totally different methods. We'll mention that in the chapter <info:property-descriptors>.
254+
````
232255

233256
## Summary
234257

235-
Objects are assigned and copied by reference. In other words, a variable stores not the "object value", but a "reference" (address in memory) for the value. So copying such a variable or passing it as a function argument copies that reference, not the object.
258+
Objects are assigned and copied by reference. In other words, a variable stores not the "object value", but a "reference" (address in memory) for the value. So copying such a variable or passing it as a function argument copies that reference, not the object itself.
236259

237260
All operations via copied references (like adding/removing properties) are performed on the same single object.
238261

1-js/04-object-basics/03-garbage-collection/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Simply put, "reachable" values are those that are accessible or usable somehow.
2323

2424
2. Any other value is considered reachable if it's reachable from a root by a reference or by a chain of references.
2525

26-
For instance, if there's an object in a global variable, and that object has a property referencing another object, that object is considered reachable. And those that it references are also reachable. Detailed examples to follow.
26+
For instance, if there's an object in a global variable, and that object has a property referencing another object, *that* object is considered reachable. And those that it references are also reachable. Detailed examples to follow.
2727

2828
There's a background process in the JavaScript engine that is called [garbage collector](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)). It monitors all objects and removes those that have become unreachable.
2929

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

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,51 +9,89 @@ 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, 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'll 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
17-
let user = {}; // the user without "address" property
19+
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, but many practical cases we'd prefer to get `undefined` instead of an error (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 to get an information about an element on the page, that 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-
// Error if the result of querySelector(...) is null
28-
let html = document.querySelector('.my-element').innerHTML;
31+
// document.querySelector('.elem') is null if there's no element
32+
let html = document.querySelector('.elem').innerHTML; // error if it's null
2933
```
3034

31-
Before `?.` appeared in the language, the `&&` operator was used to work around that.
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

33-
For example:
37+
How can we do this?
38+
39+
The obvious solution would be to check the value using `if` or the conditional operator `?`, before accessing its property, like this:
40+
41+
```js
42+
let user = {};
43+
44+
alert(user.address ? user.address.street : undefined);
45+
```
46+
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.
48+
49+
E.g. let's try getting `user.address.street.name`.
50+
51+
We need to check both `user.address` and `user.address.street`:
52+
53+
```js
54+
let user = {}; // user has no address
55+
56+
alert(user.address ? user.address.street ? user.address.street.name : null : null);
57+
```
58+
59+
That's just awful, one may even have problems understanding such code.
60+
61+
Don't even care to, as there's a better way to write it, using the `&&` operator:
3462

3563
```js run
3664
let user = {}; // user has no address
3765

38-
alert( user && user.address && user.address.street ); // undefined (no error)
66+
alert( user.address && user.address.street && user.address.street.name ); // undefined (no error)
3967
```
4068

41-
AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but is cumbersome to write.
69+
AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but also isn't ideal.
70+
71+
As you can see, property names are still duplicated in the code. E.g. in the code above, `user.address` appears three times.
72+
73+
That's why the optional chaining `?.` was added to the language. To solve this problem once and for all!
4274

4375
## Optional chaining
4476

45-
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.
4678

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

49-
Here's the safe way to access `user.address.street`:
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 `undefined`.
84+
85+
Here's the safe way to access `user.address.street` using `?.`:
5086

5187
```js run
5288
let user = {}; // user has no address
5389

5490
alert( user?.address?.street ); // undefined (no error)
5591
```
5692
93+
The code is short and clean, there's no duplication at all.
94+
5795
Reading the address with `user?.address` works even if `user` object doesn't exist:
5896
5997
```js run
@@ -65,14 +103,12 @@ alert( user?.address.street ); // undefined
65103
66104
Please note: the `?.` syntax makes optional the value before it, but not any further.
67105
68-
In the example above, `user?.` allows only `user` to be `null/undefined`.
69-
70-
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 `?.`.
71107
72108
```warn header="Don't overuse the optional chaining"
73109
We should use `?.` only where it's ok that something doesn't exist.
74110

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.
111+
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`.
76112

77113
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.
78114
```
@@ -84,7 +120,7 @@ If there's no variable `user` at all, then `user?.anything` triggers an error:
84120
// ReferenceError: user is not defined
85121
user?.address;
86122
```
87-
There must be a declaration (e.g. `let/const/var user`). The optional chaining works only for declared variables.
123+
The variable must be declared (e.g. `let/const/var user` or as a function parameter). The optional chaining works only for declared variables.
88124
````
89125

90126
## Short-circuiting
@@ -113,17 +149,20 @@ For example, `?.()` is used to call a function that may not exist.
113149
In the code below, some of our users have `admin` method, and some don't:
114150

115151
```js run
116-
let user1 = {
152+
let userAdmin = {
117153
admin() {
118154
alert("I am admin");
119155
}
120-
}
156+
};
121157

122-
let user2 = {};
158+
let userGuest = {};
159+
160+
*!*
161+
userAdmin.admin?.(); // I am admin
162+
*/!*
123163

124164
*!*
125-
user1.admin?.(); // I am admin
126-
user2.admin?.();
165+
userGuest.admin?.(); // nothing (no such method)
127166
*/!*
128167
```
129168

0 commit comments

Comments
 (0)