Skip to content

Commit d4c714c

Browse files
committed
work
1 parent 4c531b5 commit d4c714c

File tree

261 files changed

+7368
-544
lines changed

Some content is hidden

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

261 files changed

+7368
-544
lines changed

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

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -490,13 +490,13 @@ alert(*!*user.name*/!*); // 'Pete', changes are seen from the "user" reference
490490
491491
The example above demonstrates that there is only one object. Like if we had a cabinet with two keys and used one of them (`admin`) to get into it -- later using the other one (`user`) we will see things modified.
492492
493-
494-
495493
### Comparison by reference
496494
497-
The equality `==` and strict equality `===` operators for objects work exactly the same, simple way.
495+
The equality `==` and strict equality `===` operators for objects work exactly the same.
496+
497+
**Two objects are equal only if they are the same object.**
498498
499-
**Two object variables are equal only when reference the same object.**
499+
For instance, two variables reference the same object, they are equal:
500500
501501
```js run
502502
let a = {};
@@ -506,9 +506,7 @@ alert( a == b ); // true, both variables reference the same object
506506
alert( a === b ); // true
507507
```
508508
509-
In all other cases objects are non-equal, even if their content is the same.
510-
511-
For instance:
509+
And here two independent objects are not equal, even though both are empty:
512510
513511
```js run
514512
let a = {};
@@ -517,9 +515,7 @@ let b = {}; // two independent objects
517515
alert( a == b ); // false
518516
```
519517
520-
That rule only applies to object vs object equality checks.
521-
522-
For other comparisons like whether an object less/greater than another object (`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 say the truth, such comparisons occur very rarely in real code and usually are a result of a coding mistake.
518+
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 say the truth, such comparisons occur very rarely in real code and usually are a result of a coding mistake.
523519
524520
## Cloning and merging, Object.assign
525521

1-js/4-object-basics/03-object-methods/9-string-new-property/solution.md

Lines changed: 0 additions & 31 deletions
This file was deleted.

1-js/4-object-basics/03-object-methods/9-string-new-property/task.md

Lines changed: 0 additions & 18 deletions
This file was deleted.

1-js/4-object-basics/03-object-methods/article.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,6 @@ In this case `this` is `undefined` in strict mode. If we try to access `this.nam
214214

215215
In non-strict mode (if you forgot `use strict`) the value of `this` in such case will be the *global object* (`"window"` for browser, we'll study it later). This is just a historical thing that `"use strict"` fixes.
216216

217-
218217
Please note that usually a call of a function using `this` without an object is not normal, but rather a programming mistake. If a function has `this`, then it is usually meant to be called in the context of an object.
219218

220219
```smart header="The consequences of unbound `this`"
@@ -224,7 +223,6 @@ The idea of unbound, run-time evaluated `this` has both pluses and minuses. From
224223

225224
Here we are not to judge whether this language design decision is good or bad. We will understand how to work with it, how to get benefits and evade problems.
226225
```
227-
228226
## Internals: Reference Type
229227
230228
An intricate method call can loose `this`, for instance:

1-js/4-object-basics/05-constructor-new/article.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,39 @@ let user = new function() {
8585
The constructor can't be called again, because it is not saved anywhere, just created and called. So this trick aims to encapsulate the code for a single complex object only.
8686
````
8787

88+
## Dual-use constructors: new.target
89+
90+
Inside a function, we can check how it is called with `new` or without it, using a special `new.target` property.
91+
92+
It is empty for ordinary runs and equals the function if called with `new`:
93+
94+
```js run
95+
function User() {
96+
alert(new.target);
97+
}
98+
99+
User(); // undefined
100+
new User(); // function User { ... }
101+
```
102+
103+
That can be used to allow both `new` and ordinary syntax work the same:
104+
105+
106+
```js run
107+
function User(name) {
108+
if (!new.target) { // if you run me without new
109+
return new User(name); // ...I will add new for you
110+
}
111+
112+
this.name = name;
113+
}
114+
115+
let john = User("John"); // redirects call to new User
116+
alert(john.name); // John
117+
```
118+
119+
This approach is sometimes used in libraries to make the syntax more flexible. Probably not a good thing to use everywhere though, because it makes a bit less obvious what's going on for a person who's familiar with internals of `User`.
120+
88121
## Return from constructors
89122

90123
Usually, constructors do not have a `return` statement. Their task is to write all necessary stuff into `this`, and it automatically becomes the result.

1-js/4-object-basics/07-object-toprimitive/article.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ The conversion of an object to primitive value (a number or a string) is a rare
1616

1717
Just think about cases when such conversion may be necessary. For instance, numeric conversion happens when we compare an object against a primitive: `user > 18`. But what such comparison actually means? Are we going to compare `18` against user's age? Then it would be more obvious to write `user.age > 18`. And it's easier to read and understand it too.
1818

19-
Or, for a string conversion... Where does it happen? Usually, when we output an object. But simple ways of object-as-string output like `alert(user)` are only used for debugging and logging purposes. For real stuff, the output is more complicated, we may need to provide it additional parameters. That's why we usually implement it using object methods like `user.format()` or even in more advanced ways.
19+
Or, for a string conversion... Where does it happen? Usually, when we output an object. But simple ways of object-as-string output like `alert(user)` are only used for debugging and logging purposes. For real stuff, the output is more complicated, we may need to configure it with additional parameters. That's why it is usually implemented with object methods like `user.format()` or even in more advanced ways.
2020

2121
So, most of the time, it's more flexible and gives more readable code to explicitly write an object property or call a method than rely on the conversion.
2222

2323
That said, there are still valid reasons why we should know how to-primitive conversion works.
2424

25-
- Simple object-as-string output may be useable sometimes. Without a customized conversion it will show `[object Object]`.
25+
- Simple object-as-string output may be useable sometimes.
2626
- Many built-in objects implement their own to-primitive conversion, we plan to cover that.
27-
- Sometimes it just happens (on mistake?), and we should understand what's going on.
27+
- Sometimes an unexpected conversion happens, and we should understand what's going on.
2828
- Okay, the final one. There are quizzes and questions on interviews that rely on that knowledge. Looks like people think it's a good sigh that person understands Javascript if he knows type conversions well.
2929

3030
## ToPrimitive
@@ -78,7 +78,7 @@ There are 3 types (also called "hints") of object-to-primitive conversion:
7878

7979
Please note -- there are only three conversions. That simple. There is no "boolean" (all objects are `true` in boolean context) or anything else. And if we treat `"default"` and `"number"` the same, like most built-ins do, then there are only two conversions.
8080

81-
To do the conversion, Javascript tries to find and call these three object methods:
81+
To do the conversion, Javascript tries to find and call three object methods:
8282

8383
1. `Symbol.toPrimitive(hint)` if exists,
8484
2. Otherwise if hint is `"string"`, try `toString()` and `valueOf()`, whatever exists.
@@ -109,7 +109,7 @@ As we can see from the code, `user` becomes a self-descriptive string or a money
109109

110110
### toString/valueOf
111111

112-
Methods `toString` and `valueOf` come from the ancient times. That's why they are not symbols. They provide an alternative "old-style" way to implement the conversion.
112+
Methods `toString` and `valueOf` come from ancient times. That's why they are not symbols. They provide an alternative "old-style" way to implement the conversion.
113113

114114
If there's no `Symbol.toPrimitive` then Javascript tries to find them and try in the order:
115115

@@ -166,20 +166,20 @@ There is no control whether `toString()` returns exactly a string, or whether `S
166166

167167
**The only mandatory thing: these methods must return a primitive.**
168168

169-
An operation that was the reason for the conversion gets that primitive, and then continues to work with it, applying further conversions if necessary.
169+
An operation that initiated the conversion gets that primitive, and then continues to work with it, applying further conversions if necessary.
170170

171171
For instance:
172172

173-
- All mathematical operations except binary plus apply `ToNumber`:
173+
- All mathematical operations except binary plus apply `ToNumber` after `ToPrimitive` with `"number"` hint:
174174

175175
```js run
176176
let obj = {
177-
toString() { // toString used for numeric conversion in the absense of valueOf
177+
toString() { // toString handles all ToPrimitive in the absense of other methods
178178
return "2";
179179
}
180180
};
181181

182-
alert(obj * 2); // 4
182+
alert(obj * 2); // 4, ToPrimitive gives "2", then it becomes 2
183183
```
184184

185185
- Binary plus first checks if the primitive is a string, and then does concatenation, otherwise performs `ToNumber` and works with numbers.
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11

22

33
```js
4-
var leader = {
5-
name: "Василий Иванович",
4+
let user = {
5+
name: "John Smith",
66
age: 35
77
};
88

9-
var leaderStr = JSON.stringify(leader);
10-
leader = JSON.parse(leaderStr);
9+
*!*
10+
let user2 = JSON.parse(JSON.stringify(user));
11+
*/!*
1112
```
1213

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
importance: 3
1+
importance: 5
22

33
---
44

5-
# Превратите объект в JSON
5+
# Turn the object into JSON and back
66

7-
Превратите объект `leader` из примера ниже в JSON:
7+
Turn the `leader` into JSON and then read it back into another variable.
88

99
```js
10-
var leader = {
11-
name: "Василий Иванович",
10+
let user = {
11+
name: "John Smith",
1212
age: 35
1313
};
1414
```
15-
16-
После этого прочитайте получившуюся строку обратно в объект.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
2+
```js run
3+
let room = {
4+
number: 23
5+
};
6+
7+
let meetup = {
8+
title: "Conference",
9+
occupiedBy: [{name: "John"}, {name: "Alice"}],
10+
place: room
11+
};
12+
13+
room.occupiedBy = meetup;
14+
meetup.self = meetup;
15+
16+
alert( JSON.stringify(meetup, function replacer(key, value) {
17+
return (key != "" && value == meetup) ? undefined : value;
18+
}));
19+
20+
/*
21+
{
22+
"title":"Conference",
23+
"occupiedBy":[{"name":"John"},{"name":"Alice"}],
24+
"place":{"number":23}
25+
}
26+
*/
27+
```
28+
29+
Here we also need to test `key==""` to exclude the first call where it is normal that `value` is `meetup`.
30+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
importance: 5
2+
3+
---
4+
5+
# Exclude backreferences
6+
7+
In simple cases of circular references, we can exclude an offending property from serialization by its name.
8+
9+
But sometimes there are many backreferences. And names may be used both in circular references and normal properties.
10+
11+
Write `replacer` function to stringify everything, but remove properties that reference `meetup`:
12+
13+
```js run
14+
let room = {
15+
number: 23
16+
};
17+
18+
let meetup = {
19+
title: "Conference",
20+
occupiedBy: [{name: "John"}, {name: "Alice"}],
21+
place: room
22+
};
23+
24+
*!*
25+
// circular references
26+
room.occupiedBy = meetup;
27+
meetup.self = meetup;
28+
*/!*
29+
30+
alert( JSON.stringify(meetup, function replacer(key, value) {
31+
/* your code */
32+
}));
33+
34+
/* result should be:
35+
{
36+
"title":"Conference",
37+
"occupiedBy":[{"name":"John"},{"name":"Alice"}],
38+
"place":{"number":23}
39+
}
40+
*/
41+
```
42+

0 commit comments

Comments
 (0)