Skip to content

Commit 4a65cf8

Browse files
authored
Update article.md
1 parent 6477142 commit 4a65cf8

1 file changed

Lines changed: 93 additions & 90 deletions

File tree

1-js/09-classes/07-mixins/article.md

Lines changed: 93 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,105 @@
11
# Примесь
22

3-
В JavaScript мы можем использовать наследование только от одного объекта. Объект имеет единственный [[Prototype]]. И класс может расширить только один другой класс.
3+
В JavaScript мы можем использовать наследование только от одного объекта. Объект имеет единственный `[[Prototype]]`. И класс может расширить только один другой класс.
44

5-
Иногда это может ограничивать нас. Например, у нас есть класс StreetSweeper и класс Bicycle, и хотим создать StreetSweepingBicycle.
5+
Иногда это может ограничивать нас. Например, у нас есть класс `StreetSweeper` и класс `Bicycle`, и хотим создать `StreetSweepingBicycle`.
66

7-
Или, поговорим о программировании, у нас есть класс Renderer, который реализует шаблон и класс EventEmitter реализующий событие. И мы хотим объединить их функционалы вместе в классе Page. Создадим страницу, которая будет использовать шаблон, и использовать событие.
7+
Или, поговорим о программировании, у нас есть класс `Renderer`, который реализует шаблон и класс `EventEmitter` реализующий событие. И мы хотим объединить их функционалы вместе в классе `Page`. Создадим страницу, которая будет использовать шаблон, и использовать событие.
88

99
Для таких случаев существует "примесь".
1010

1111
Как говориться в Википедии [примесь](https://ru.wikipedia.org/wiki/Mixin) является классом, который имеет методы и мы можем их использовать в других классов, без необходимости быть родителем этих классов.
1212

13-
Другими словами примесь определяет методы, которые реализуют определенное поведение. Мы не используем его в одиночку, а используем его, чтобы добавить другим классам больше функционала.
13+
Другими словами *примесь* определяет методы, которые реализуют определенное поведение. Мы не используем его в одиночку, а используем его, чтобы добавить другим классам больше функционала.
1414

1515
## Пример примеси
1616

1717
Простой путь создать примесь в JavaScript - это создать объект с использующимися методами, так что мы легко можем объединить их в прототип любого класса.
1818

19-
В примере ниже примесь sayHiMixin имеет методы для речи User'a:
19+
В примере ниже примесь `sayHiMixin` имеет методы для речи класса `User`:
2020

21-
js run
21+
```js run
2222
*!*
2323
// примесь
2424
*/!*
2525
let sayHiMixin = {
26-
sayHi() {
27-
alert( Hello ${this.name} );
28-
},
29-
sayBye() {
30-
alert( Bye ${this.name} );
31-
}
26+
sayHi() {
27+
alert(`Hello ${this.name}`);
28+
},
29+
sayBye() {
30+
alert(`Bye ${this.name}`);
31+
}
3232
};
3333

3434
*!*
3535
// использование:
3636
*/!*
3737
class User {
38-
constructor(name) {
39-
this.name = name;
40-
}
38+
constructor(name) {
39+
this.name = name;
40+
}
4141
}
4242

4343
// копируем методы
4444
Object.assign(User.prototype, sayHiMixin);
4545

4646
// сейчас User можем сказать hi
4747
new User("Dude").sayHi(); // Hello Dude!
48+
```
4849

49-
Это не наследование, а простой способ скопировать методы. Таким образом, класс User может расширять другие классы и так же содержать в себе методы от примеси, например:
50+
Это не наследование, а простой способ скопировать методы. Таким образом, класс `User` может расширять другие классы и так же содержать в себе методы от примеси, например:
5051

51-
js
52+
```js
5253
class User extends Person {
5354
// ...
5455
}
5556

5657
Object.assign(User.prototype, sayHiMixin);
58+
```
5759

5860
Примеси могут использовать наследование между собой.
5961

60-
В примере ниже sayHiMixin наследуется от sayMixin :
62+
В примере ниже `sayHiMixin` наследуется от `sayMixin` :
6163

62-
js run
64+
```js run
6365
let sayMixin = {
64-
say(phrase) {
65-
alert(phrase);
66-
}
66+
say(phrase) {
67+
alert(phrase);
68+
}
6769
};
6870

6971
let sayHiMixin = {
70-
__proto__: sayMixin, // (или мы можем использовать Object.create для определения прототипа)
71-
72-
sayHi() {
73-
*!*
74-
// вызываем метод родителя
75-
*/!*
76-
super.say( Hello ${this.name} );
77-
},
78-
sayBye() {
79-
super.say( Bye ${this.name} );
80-
}
72+
__proto__: sayMixin, // (или мы можем использовать Object.create для определения прототипа)
73+
74+
sayHi() {
75+
*!*
76+
// вызываем метод родителя
77+
*/!*
78+
super.say(`Hello ${this.name}`);
79+
},
80+
sayBye() {
81+
super.say(`Bye ${this.name}`);
82+
}
8183
};
8284

8385
class User {
84-
constructor(name) {
85-
this.name = name;
86-
}
86+
constructor(name) {
87+
this.name = name;
88+
}
8789
}
8890

8991
// копируем методы
9092
Object.assign(User.prototype, sayHiMixin);
9193

9294
// сейчас User может сказать hi
9395
new User("Dude").sayHi(); // Hello Dude!
96+
```
9497

95-
Обратите внимание, что мы вызвали родительский метод super.say() из 'sayHiMixin' в прототипе другой примеси, а не в классе.
98+
Обратите внимание, что мы вызвали родительский метод `super.say()` из `sayHiMixin` в прототипе другой примеси, а не в классе.
9699

97100
![](mixin-inheritance.png)
98101

99-
Это связано с тем, что методы из sayHiMixin имеют установку [[HomeObject]]. А super на самом деле означает sayHiMixin.__ proto__, а не User.__ proto__.
102+
Это связано с тем, что методы из `sayHiMixin` имеют установку `[[HomeObject]]`. А `super` на самом деле означает `sayHiMixin.__ proto__`, а не `User.__ proto__`.
100103

101104
## Примесь события
102105

@@ -108,72 +111,71 @@ new User("Dude").sayHi(); // Hello Dude!
108111

109112
Событие может иметь имя, необязательно, и связь между некоторыми дополнительными данными.
110113

111-
Например объект user может генерировать события "login", когда посетитель входит. А другой объект calendar может захотеть получать его события, чтобы загрузить календарь для вошедшего человека.
114+
Например объект `user` может генерировать события `"login"`, когда посетитель входит. А другой объект `calendar` может захотеть получать его события, чтобы загрузить календарь для вошедшего человека.
112115

113-
Или menu может генерировать событие "select", когда меню элемент выбран, или другие объекты могут захотеть получить эту информацию и отреагировать на это событие.
116+
Или `menu` может генерировать событие `"select"`, когда меню элемент выбран, или другие объекты могут захотеть получить эту информацию и отреагировать на это событие.
114117

115118
События — это способ «поделиться информацией» со всеми, кто этого захочет. Они могут быть полезны в любом классе, поэтому давайте сделаем для них пример:
116119

117-
js run
120+
```js run
118121
let eventMixin = {
119-
/**
120-
* Опишем события, используя:
121-
* menu.on('select', function(item) { ... }
122-
*/
123-
on(eventName, handler) {
124-
if (!this._eventHandlers) this._eventHandlers = {};
125-
if (!this._eventHandlers[eventName]) {
126-
this._eventHandlers[eventName] = [];
127-
}
128-
this._eventHandlers[eventName].push(handler);
129-
},
130-
131-
/**
132-
* Закроем событие, используя:
133-
* menu.off('select', handler)
134-
*/
135-
off(eventName, handler) {
136-
let handlers = this._eventHandlers && this._eventHandlers[eventName];
137-
if (!handlers) return;
138-
for (let i = 0; i< handlers.length; i++) {
139-
if (handlers[i] === handler) {
140-
handlers.splice(i--, 1);
141-
}
142-
}
143-
},
144-
145-
/**
146-
* Создадим событие и прикрепим данные
147-
* this.trigger('select', data1, data2);
148-
*/
149-
trigger(eventName, ...args) {
150-
if (!this._eventHandlers || !this._eventHandlers[eventName]) {
151-
return; // no handlers for that event name
152-
// без обработчиков для этого события
153-
}
154-
155-
// вызовем обработчиков
156-
this._eventHandlers[eventName].forEach(handler => handler.apply(this, args));
157-
}
122+
/**
123+
* Опишем события, используя:
124+
* menu.on('select', function(item) { ... }
125+
*/
126+
on(eventName, handler) {
127+
if (!this._eventHandlers) this._eventHandlers = {};
128+
if (!this._eventHandlers[eventName]) {
129+
this._eventHandlers[eventName] = [];
130+
}
131+
this._eventHandlers[eventName].push(handler);
132+
},
133+
134+
/**
135+
* Закроем событие, используя:
136+
* menu.off('select', handler)
137+
*/
138+
off(eventName, handler) {
139+
let handlers = this._eventHandlers && this._eventHandlers[eventName];
140+
if (!handlers) return;
141+
for (let i = 0; i< handlers.length; i++) {
142+
if (handlers[i] === handler) {
143+
handlers.splice(i--, 1);
144+
}
145+
}
146+
},
147+
148+
/**
149+
* Создадим событие и прикрепим данные
150+
* this.trigger('select', data1, data2);
151+
*/
152+
trigger(eventName, ...args) {
153+
if (!this._eventHandlers || !this._eventHandlers[eventName]) {
154+
return; // без обработчиков для этого события
155+
}
156+
157+
// вызовем обработчиков
158+
this._eventHandlers[eventName].forEach(handler => handler.apply(this, args));
159+
}
158160
};
161+
```
159162

160163
И так у нас 3 метода:
161164

162-
1. .on(eventName, handler) -- назначили функцию handler, чтобы запустить событие с этим именем. И храним обработчиков в _eventHandlers
163-
свойстве.
165+
1. `.on(eventName, handler)` -- назначили функцию `handler`, чтобы запустить событие с этим именем. И храним обработчиков в `_eventHandlers` свойстве.
164166

165-
2. .off(eventName, handler) -- удаляем функцию из списка обработчиков
167+
2. `.off(eventName, handler)` -- удаляем функцию из списка обработчиков
166168

167-
3. .trigger(eventName, ...args) -- генерируем событие: все назначенные обработчики вызываются и в args передаются в качестве аргументов.
169+
3. `.trigger(eventName, ...args)` -- генерируем событие: все назначенные обработчики вызываются и в `args` передаются в качестве аргументов.
168170

169171
Использование:
170172

171-
js run
173+
```js run
172174
// Создадим класс
173175
class Menu {
174-
choose(value) {
175-
this.trigger("select", value);
176-
}
176+
choose(value) {
177+
this.trigger("select", value);
178+
}
177179
}
178180
// Добавим примесь
179181
Object.assign(Menu.prototype, eventMixin);
@@ -187,10 +189,11 @@ menu.on("select", value => alert( Value selected: ${value} ));
187189

188190
// Запустили событие => покажет выбранное значение: 123
189191
menu.choose("123"); // значение выбрано
192+
```
190193

191-
Сейчас у нас есть код, который реагирует на выбор пользователя и мы можем связать его с menu.on(...).
194+
Сейчас у нас есть код, который реагирует на выбор пользователя и мы можем связать его с `menu.on(...)`.
192195

193-
И eventMixin может добавить поведение в любой класс какой мы хотим, без вмешательства в цепочку наследования.
196+
И `eventMixin` может добавить поведение в любой класс какой мы хотим, без вмешательства в цепочку наследования.
194197

195198
## Итого
196199

0 commit comments

Comments
 (0)