You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1-js/09-classes/03-static-properties-methods/article.md
+1-1
Original file line number
Diff line number
Diff line change
@@ -224,6 +224,6 @@ MyClass.property = ...
224
224
MyClass.method=...
225
225
```
226
226
227
-
Static properties are inherited.
227
+
Static properties and methods are inherited.
228
228
229
229
For `class B extends A` the prototype of the class `B` itself points to `A`: `B.[[Prototype]] = A`. So if a field is not found in `B`, the search continues in `A`.
Copy file name to clipboardExpand all lines: 1-js/09-classes/04-private-protected-properties-methods/article.md
+2-2
Original file line number
Diff line number
Diff line change
@@ -53,7 +53,7 @@ In JavaScript, there are two types of object fields (properties and methods):
53
53
- Public: accessible from anywhere. They comprise the external interface. Till now we were only using public properties and methods.
54
54
- Private: accessible only from inside the class. These are for the internal interface.
55
55
56
-
In many other languages there also exist "protected" fields: accessible only from inside the class and those extending it. 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.
56
+
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.
57
57
58
58
Protected fields are not implemented in JavaScript on the language level, but in practice they are very convenient, so they are emulated.
59
59
@@ -297,7 +297,7 @@ Supportable
297
297
298
298
**If we strictly delimit the internal interface, then the developer of the class can freely change its internal properties and methods, even without informing the users.**
299
299
300
-
If you're a developer of such class, it's great to know that private methods can be safely renamed, their parameters can be changed, and even removed, because no external code depends on them.
300
+
If you're a developer of such class, it's great to know that private methods can be safely renamed, their parameters can be changed, and even removed, because no external code depends on them.
301
301
302
302
For users, when a new version comes out, it may be a total overhaul internally, but still simple to upgrade if the external interface is the same.
Copy file name to clipboardExpand all lines: 1-js/09-classes/05-extend-natives/article.md
+8-2
Original file line number
Diff line number
Diff line change
@@ -21,14 +21,14 @@ alert(filteredArr); // 10, 50
21
21
alert(filteredArr.isEmpty()); // false
22
22
```
23
23
24
-
Please note a very interesting thing. Built-in methods like `filter`, `map` and others -- return new objects of exactly the inherited type. They rely on the `constructor` property to do so.
24
+
Please note a very interesting thing. Built-in methods like `filter`, `map` and others -- return new objects of exactly the inherited type`PowerArray`. Their internal implementation uses object `constructor` property for that.
25
25
26
26
In the example above,
27
27
```js
28
28
arr.constructor=== PowerArray
29
29
```
30
30
31
-
So when `arr.filter()` is called, it internally creates the new array of results using exactly `new PowerArray`, not basic `Array`. That's actually very cool, because we can keep using `PowerArray` methods further on the result.
31
+
When `arr.filter()` is called, it internally creates the new array of results using exactly `arr.constructor`, not basic `Array`. That's actually very cool, because we can keep using `PowerArray` methods further on the result.
32
32
33
33
Even more, we can customize that behavior.
34
34
@@ -64,6 +64,10 @@ alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function
64
64
65
65
As you can see, now `.filter` returns `Array`. So the extended functionality is not passed any further.
66
66
67
+
```smart header="Other collections work similarly"
68
+
Other collections, such as `Map` and `Set`, work alike. They also use `Symbol.species`.
69
+
```
70
+
67
71
## No static inheritance in built-ins
68
72
69
73
Built-in objects have their own static methods, for instance `Object.keys`, `Array.isArray` etc.
@@ -81,3 +85,5 @@ Here's the picture structure for `Date` and `Object`:
81
85

82
86
83
87
As you can see, there's no link between `Date` and `Object`. They are independent, only `Date.prototype` inherits from `Object.prototype`.
88
+
89
+
That's an important difference of inheritance between built-in objects compared to what we get with `extends`.
Please note that `arr` also belongs to the `Object` class. That's because `Array` prototypally inherits from `Object`.
48
48
49
-
The`instanceof` operator examines the prototype chain for the check, but we can set a custom logic in the static method `Symbol.hasInstance`.
49
+
Normally,`instanceof` operator examines the prototype chain for the check. We can also set a custom logic in the static method `Symbol.hasInstance`.
50
50
51
51
The algorithm of `obj instanceof Class` works roughly as follows:
52
52
53
-
1. If there's a static method `Symbol.hasInstance`, then just call it: `Class[Symbol.hasInstance](obj)`. It should return either `true` or `false`. We're done.
54
-
For example:
53
+
1. If there's a static method `Symbol.hasInstance`, then just call it: `Class[Symbol.hasInstance](obj)`. It should return either `true` or `false`, and we're done. That's how we can customize the behavior of `instanceof`.
54
+
55
+
For example:
55
56
56
57
```js run
57
-
// setup instanceOf check that assumes that anything that canEat is an animal
58
+
// setup instanceOf check that assumes that
59
+
// anything with canEat property is an animal
58
60
classAnimal {
59
61
static [Symbol.hasInstance](obj) {
60
62
if (obj.canEat) returntrue;
@@ -68,17 +70,19 @@ The algorithm of `obj instanceof Class` works roughly as follows:
68
70
69
71
2. Most classes do not have `Symbol.hasInstance`. In that case, the standard logic is used:`obj instanceOf Class` checks whether `Class.prototype` equals to one of prototypes in the `obj` prototype chain.
Here we used [call](mdn:js/function/call) as described in the chapter [](info:call-apply-decorators) to execute the function `objectToString` in the context `this=arr`.
@@ -196,11 +201,11 @@ As you can see, the result is exactly `Symbol.toStringTag` (if exists), wrapped
196
201
197
202
At the end we have "typeof on steroids" that not only works for primitive data types, but also for built-in objects and even can be customized.
198
203
199
-
It can be used instead of `instanceof` for built-in objects when we want to get the type as a string rather than just to check.
204
+
We can use `{}.toString.call` instead of `instanceof` for built-in objects when we want to get the type as a string rather than just to check.
200
205
201
206
## Summary
202
207
203
-
Let's recap the type-checking methods that we know:
208
+
Let's summarize the type-checking methods that we know:
Copy file name to clipboardExpand all lines: 1-js/09-classes/07-mixins/article.md
+10-8
Original file line number
Diff line number
Diff line change
@@ -2,9 +2,9 @@
2
2
3
3
In JavaScript we can only inherit from a single object. There can be only one `[[Prototype]]` for an object. And a class may extend only one other class.
4
4
5
-
But sometimes that feels limiting. For instance, I have a class `StreetSweeper` and a class `Bicycle`, and want to make a `StreetSweepingBicycle`.
5
+
But sometimes that feels limiting. For instance, I have a class `StreetSweeper` and a class `Bicycle`, and want to make their mix: a `StreetSweepingBicycle`.
6
6
7
-
Or, talking about programming, we have a class `User` and a class `EventEmitter` that implements event generation, and we'd like to add the functionality of `EventEmitter` to `User`, so that our users can emit events.
7
+
Or we have a class `User` and a class `EventEmitter` that implements event generation, and we'd like to add the functionality of `EventEmitter` to `User`, so that our users can emit events.
8
8
9
9
There's a concept that can help here, called "mixins".
10
10
@@ -14,7 +14,7 @@ In other words, a *mixin* provides methods that implement a certain behavior, bu
14
14
15
15
## A mixin example
16
16
17
-
The simplest way to make a mixin in JavaScript is to make an object with useful methods, so that we can easily merge them into a prototype of any class.
17
+
The simplest way to implement a mixin in JavaScript is to make an object with useful methods, so that we can easily merge them into a prototype of any class.
18
18
19
19
For instance here the mixin `sayHiMixin` is used to add some "speech" for `User`:
Please note that the call to the parent method `super.say()` from `sayHiMixin` looks for the method in the prototype of that mixin, not the class.
98
+
Please note that the call to the parent method `super.say()` from `sayHiMixin` (at lines labelled with `(*)`) looks for the method in the prototype of that mixin, not the class.
99
+
100
+
Here's the diagram (see the right part):
99
101
100
102

101
103
102
-
That's because methods `sayHi` and `sayBye` were initially created in `sayHiMixin`. So their `[[HomeObject]]` internal property references `sayHiMixin`, as shown on the picture above.
104
+
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.
103
105
104
106
As `super` looks for parent methods in `[[HomeObject]].[[Prototype]]`, that means it searches `sayHiMixin.[[Prototype]]`, not `User.[[Prototype]]`.
105
107
@@ -199,7 +201,7 @@ And `eventMixin` mixin makes it easy to add such behavior to as many classes as
199
201
200
202
*Mixin* -- is a generic object-oriented programming term: a class that contains methods for other classes.
201
203
202
-
Some other languages like e.g. Python allow to create mixins using multiple inheritance. JavaScript does not support multiple inheritance, but mixins can be implemented by copying methods into prototype.
204
+
Some other languages like allow multiple inheritance. JavaScript does not support multiple inheritance, but mixins can be implemented by copying methods into prototype.
203
205
204
206
We can use mixins as a way to augment a class by multiple behaviors, like event-handling as we have seen above.
0 commit comments