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/07-object-oriented-programming/09-class/article.md
+83-36Lines changed: 83 additions & 36 deletions
Original file line number
Diff line number
Diff line change
@@ -43,14 +43,16 @@ let user = new User("John");
43
43
user.sayHi();
44
44
```
45
45
46
-
It's easy to see that the two examples are alike. So, what exactly does `class` do? We may think that it defines a new language-level entity, but that would be wrong.
46
+
It's easy to see that the two examples are alike. Just please note that methods in a class do not have a comma between them. Notice developers sometimes forget it and put a comma between class methods, and things don't work. That's not a literal object, but a class syntax.
47
+
48
+
So, what exactly does `class` do? We may think that it defines a new language-level entity, but that would be wrong.
47
49
48
50
The `class User {...}` here actually does two things:
49
51
50
52
1. Declares a variable `User` that references the function named `"constructor"`.
51
53
2. Puts into `User.prototype` methods listed in the definition. Here it includes `sayHi` and the `constructor`.
52
54
53
-
Here's some code to demonstrate that:
55
+
Here's the code to dig into the class and see that:
Here's the illustration of what `class User` creates:
73
75
74
76

75
77
76
-
So `class` is a special syntax to define the constructor with prototype methods.
77
78
78
-
...But not only that. There are minor tweaks here and there to ensure the right usage.
79
79
80
-
For instance, the `constructor` function can't be called without `new`:
80
+
So `class` is a special syntax to define a constructor together with its prototype methods.
81
+
82
+
...But not only that. There are minor tweaks here and there:
83
+
84
+
Constructors require `new`
85
+
: Unlike a regular function, a class `constructor` can't be called without `new`:
86
+
81
87
```js run
82
88
classUser {
83
89
constructor() {}
@@ -87,23 +93,19 @@ alert(typeof User); // function
87
93
User(); // Error: Class constructor User cannot be invoked without 'new'
88
94
```
89
95
90
-
```smart header="Outputting a class"
91
-
If we output it like `alert(User)`, some engines show `"class User..."`, while others show `"function User..."`.
96
+
Different string output
97
+
: If we output it like `alert(User)`, some engines show `"class User..."`, while others show `"function User..."`.
92
98
93
99
Please don't be confused: the string representation may vary, but that's still a function, there is no separate "class" entity in JavaScript language.
94
-
```
95
100
96
-
```smart header="Class methods are non-enumerable"
97
-
Class definition sets `enumerable` flag to `false` for all methods in the `"prototype"`. That's good, because if we `for..in` over an object, we usually don't want its class methods.
98
-
```
101
+
Class methods are non-enumerable
102
+
: A class definition sets `enumerable` flag to `false` for all methods in the `"prototype"`. That's good, because if we `for..in` over an object, we usually don't want its class methods.
99
103
100
-
```smart header="What if there's no constructor?"
101
-
If there's no `constructor` in the `class` construct, then an empty function is generated, same as if we had written `constructor() {}`.
102
-
```
104
+
Classes have a default `constructor() {}`
105
+
: If there's no `constructor` in the `class` construct, then an empty function is generated, same as if we had written `constructor() {}`.
103
106
104
-
```smart header="Classes always `use strict`"
105
-
All code inside the class construct is automatically in strict mode.
106
-
```
107
+
Classes always `use strict`
108
+
: All code inside the class construct is automatically in strict mode.
107
109
108
110
### Getters/setters
109
111
@@ -141,13 +143,26 @@ alert(user.name); // John
141
143
user =newUser(""); // Name too short.
142
144
```
143
145
144
-
### Only methods
146
+
Internally, getters and setters are also created on the `User` prototype, like this:
145
147
146
-
Unlike object literals, no `property:value` assignments are allowed inside `class`. There may be only methods (without a comma between them) and getters/setters.
148
+
```js
149
+
Object.defineProperty(User.prototype, {
150
+
name: {
151
+
get() {
152
+
returnthis._name
153
+
},
154
+
set(name) {
155
+
// ...
156
+
}
157
+
}
158
+
});
159
+
```
147
160
148
-
The idea is that everything inside `class` goes to the prototype. And the prototype should store methods only, which are shared between objects. The data describing a concrete object state should reside in individual objects.
161
+
### Only methods
149
162
150
-
If we really insist on putting a non-function value into the prototype, then `class` can't help here. We can alter `prototype` manually though, like this:
163
+
Unlike object literals, no `property:value` assignments are allowed inside `class`. There may be only methods and getters/setters. There is some work going on in the specification to lift that limitation, but it's not yet there.
164
+
165
+
If we really need to put a non-function value into the prototype, then we can alter `prototype` manually, like this:
151
166
152
167
```js run
153
168
classUser { }
@@ -157,9 +172,9 @@ User.prototype.test = 5;
157
172
alert( newUser().test ); // 5
158
173
```
159
174
160
-
So, technically that's possible, but we should know why we're doing it.
175
+
So, technically that's possible, but we should know why we're doing it. Such properties will be shared among all objects of the class.
161
176
162
-
An alternative here would be to use a getter:
177
+
An "in-class" alternative is to use a getter:
163
178
164
179
```js run
165
180
classUser {
@@ -171,7 +186,7 @@ class User {
171
186
alert( newUser().test ); // 5
172
187
```
173
188
174
-
From the external code, the usage is the same. But the getter variant is probably a bit slower.
189
+
From the external code, the usage is the same. But the getter variant is a bit slower.
175
190
176
191
## Class Expression
177
192
@@ -180,8 +195,9 @@ Just like functions, classes can be defined inside another expression, passed ar
180
195
Here's a class-returning function ("class factory"):
181
196
182
197
```js run
183
-
functiongetClass(phrase) {
198
+
functionmakeClass(phrase) {
184
199
*!*
200
+
// declare a class and return it
185
201
returnclass {
186
202
sayHi() {
187
203
alert(phrase);
@@ -190,30 +206,31 @@ function getClass(phrase) {
190
206
*/!*
191
207
}
192
208
193
-
let User =getClass("Hello");
209
+
let User =makeClass("Hello");
194
210
195
211
newUser().sayHi(); // Hello
196
212
```
197
213
198
-
That's quite normal if we recall that `class` is just a special form of function-with-prototype definition.
214
+
That's quite normal if we recall that `class` is just a special form of a function-with-prototype definition.
199
215
200
216
And, like Named Function Expressions, such classes also may have a name, that is visible inside that class only:
201
217
202
218
```js run
219
+
// "Named Class Expression" (alas, no such term, but that's what's going on)
203
220
let User =class*!*MyClass*/!* {
204
221
sayHi() {
205
-
alert(MyClass);
222
+
alert(MyClass);// MyClass is visible only inside the class
Here `Article.compare` stands "over" the articles, as a means to compare them.
293
+
Here `Article.compare` stands "over" the articles, as a means to compare them. It's not a method of an article, but rather of the whole class.
294
+
295
+
Another example would be a so-called "factory" method. Imagine, we need few ways to create an article:
277
296
278
-
Another example would be a so-called "factory" method, that creates an object with specific parameters.
297
+
1. Create by given parameters (`title`, `date` etc).
298
+
2. Create an empty article with today's date.
299
+
3. ...
300
+
301
+
The first way can be implemented by the constructor. And for the second one we can make a static method of the class.
279
302
280
303
Like `Article.createTodays()` here:
281
304
@@ -299,12 +322,36 @@ let article = Article.createTodays();
299
322
alert( articles.title ); // Todays digest
300
323
```
301
324
302
-
Now every time we need to create a todays digest, we can call `Article.createTodays()`.
325
+
Now every time we need to create a todays digest, we can call `Article.createTodays()`. Once again, that's not a method of an article, but a method of the whole class.
303
326
304
-
Static methods are often used in database-related classes to search/save/remove entries from the database, like this:
327
+
Static methods are also used in database-related classes to search/save/remove entries from the database, like this:
305
328
306
329
```js
307
330
// assuming Article is a special class for managing articles
308
331
// static method to remove the article:
309
332
Article.remove({id:12345});
310
333
```
334
+
335
+
## Summary
336
+
337
+
The basic class syntax looks like this:
338
+
339
+
```js
340
+
classMyClass {
341
+
constructor(...) {
342
+
// ...
343
+
}
344
+
method1(...) {}
345
+
method2(...) {}
346
+
getsomething(...) {}
347
+
setsomething(...) {}
348
+
staticstaticMethod(..) {}
349
+
// ...
350
+
}
351
+
```
352
+
353
+
The value of `MyClass` is a function provided as `constructor`. If there's no `constructor`, then an empty function.
354
+
355
+
In any case, methods listed in the class declaration become members of its `prototype`, with the exception of static methods that are written into the function itself and callable as `MyClass.staticMethod()`. Static methods are used when we need a function bound to a class, but not to any object of that class.
356
+
357
+
In the next chapter we'll learn more about classes, including inheritance.
Copy file name to clipboardExpand all lines: 1-js/07-object-oriented-programming/13-mixins/article.md
+25-19Lines changed: 25 additions & 19 deletions
Original file line number
Diff line number
Diff line change
@@ -1,18 +1,20 @@
1
1
# Mixins
2
2
3
-
In JavaScript we can only inherit from a single object. There can be only one `[[Prototype]]`.
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 we need such kind of thing. For instance, we have a code that implements events exchange or templating, and we'd like to be able to add these capabilities to any class easily.
5
+
But sometimes that feels limiting. For instance, I have a class `StreetSweeper` and a class `Bycicle`, and want to make a `StreetSweepingBycicle`.
6
6
7
-
What can help here is *mixins*.
7
+
Or, talking about programming, we have a class `Renderer` that implements templating and a class `EventEmitter` that implements event handling, and want to merge these functionalities together with a class `Page`, to make a page that can use templates and emit events.
8
8
9
-
As [defined in Wikipedia](https://en.wikipedia.org/wiki/Mixin), a *mixin* is a class that contains methods for use by other classes without having to be the parent class of those other classes.
9
+
There's a concept that can help here, called "mixins".
10
10
11
-
In other words, a *mixin* is a class that implements a certain behavior. But we do not use it alone, we use it to add the behavior to other classes.
11
+
As defined in Wikipedia, a [mixin](https://en.wikipedia.org/wiki/Mixin) is a class that contains methods for use by other classes without having to be the parent class of those other classes.
12
+
13
+
In other words, a *mixin* provides methods that implement a certain behavior, but we do not use it alone, we use it to add the behavior to other classes.
12
14
13
15
## A mixin example
14
16
15
-
The simplest way to make a mixin in JavaScript -- is to make an object with useful methods, that we can just copy into the prototype.
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.
16
18
17
19
For instance here the mixin `sayHiMixin` is used to add some "speech" for `User`:
There's no inheritance, there's a simple method copying. So `User` may extend some other class and also include the mixin to "mix-in" the additional methods.
50
+
There's no inheritance, but a simple method copying. So `User` may extend some other class and also include the mixin to "mix-in" the additional methods, like this:
51
+
52
+
```js
53
+
classUserextendsPerson {
54
+
// ...
55
+
}
56
+
57
+
Object.assign(User.prototype, sayHiMixin);
58
+
```
49
59
50
-
Mixins also can make use of inheritance.
60
+
Mixins can make use of inheritance inside themselves.
51
61
52
62
For instance, here `sayHiMixin` inherits from `sayMixin`:
53
63
@@ -59,8 +69,7 @@ let sayMixin = {
59
69
};
60
70
61
71
let sayHiMixin = {
62
-
// can use any way of prototype setting here
63
-
__proto__: sayMixin,
72
+
__proto__: sayMixin, // (or we could use Object.create to set the prototype here)
64
73
65
74
sayHi() {
66
75
*!*
@@ -94,25 +103,22 @@ That's because methods from `sayHiMixin` have `[[HomeObject]]` set to it. So `su
94
103
95
104
## EventMixin
96
105
97
-
Now a mixin for the real life.
106
+
Now let's make a mixin for real life.
98
107
99
108
The important feature of many objects is working with events.
100
109
101
-
That is: an object should have a method to "generate an event" when something important happens to it, and other objects should be able to "subscribe" to receive such notifications.
110
+
That is: an object should have a method to "generate an event" when something important happens to it, and other objects should be able to "listen" to such events.
102
111
103
-
An event must have a name and, if necessary, the attached data.
112
+
An event must have a name and, optionally, bundle some additional data.
104
113
105
-
For instance, an object `user` can generate an event `"login"` when the visitor logs in. And an object `calendar` may want to receive such notifications and load the information about that visitor.
114
+
For instance, an object `user` can generate an event `"login"` when the visitor logs in. And another object `calendar` may want to receive such events to load the calendar for the logged-in person.
106
115
107
-
Or, the object`menu` can generate the event `"select"` when a menu item is selected, and other objects may want to get that information and react on that event.
116
+
Or, a`menu` can generate the event `"select"` when a menu item is selected, and other objects may want to get that information and react on that event.
108
117
109
-
Events is a way to "share information" with anyone who wants it.
110
-
111
-
Here is `eventMixin` that implements the corresponding methods:
118
+
Events is a way to "share information" with anyone who wants it. They can be useful in any class, so let's make a mixin for them:
0 commit comments