Skip to content

Commit cb4339d

Browse files
committed
ревью
1 parent 8093d86 commit cb4339d

2 files changed

Lines changed: 34 additions & 30 deletions

File tree

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

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
# Примеси
22

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

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

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

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

11-
Как говорится в Википедии, [примесь](https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%81%D1%8C_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)) является классом, который имеет методы, и мы можем использовать эти методы в других классах, не будучи родителем тех классов.
11+
По определению из Википедии, [примесь](https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%81%D1%8C_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)) - это класс, методы которого предназначены для использования в других классах, причём без наследования от примеси.
1212

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

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

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

1919
В примере ниже примесь `sayHiMixin` имеет методы для придания объектам класса `User` возможности вести разговор:
2020

@@ -47,7 +47,9 @@ Object.assign(User.prototype, sayHiMixin);
4747
new User("Dude").sayHi(); // Hello Dude!
4848
```
4949

50-
Это не наследование, а просто скопированные методы. Таким образом, класс `User` может расширять другие классы и также содержать в себе методы от примеси, например:
50+
Это не наследование, а просто копирование методов. Таким образом, класс `User` может расширять другие классы, но при этом также включать в себя примеси, "подмешивающие" другие методы.
51+
52+
Например:
5153

5254
```js
5355
class User extends Person {
@@ -57,7 +59,7 @@ class User extends Person {
5759
Object.assign(User.prototype, sayHiMixin);
5860
```
5961

60-
Примеси могут использовать наследование между собой.
62+
Примеси могут наследовать друг другу.
6163

6264
В примере ниже `sayHiMixin` наследуется от `sayMixin`:
6365

@@ -69,7 +71,7 @@ let sayMixin = {
6971
};
7072

7173
let sayHiMixin = {
72-
__proto__: sayMixin, // (или мы можем использовать Object.create для определения прототипа)
74+
__proto__: sayMixin, // (или мы можем использовать Object.create для задания прототипа)
7375

7476
sayHi() {
7577
*!*
@@ -95,32 +97,34 @@ Object.assign(User.prototype, sayHiMixin);
9597
new User("Dude").sayHi(); // Hello Dude!
9698
```
9799

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

100102
![](mixin-inheritance.png)
101103

102-
Это связано с тем, что методы из `sayHiMixin` имеют установленное свойство `[[HomeObject]]`. А `super` на самом деле означает `sayHiMixin.__ proto__`, а не `User.__ proto__`.
104+
Это связано с тем, что методы `sayHi` и `sayBye` были изначально созданы в объекте `sayHiMixin`. Так что их внутреннее свойство `[[HomeObject]]` ссылается на `sayHiMixin`, как показано на картинке выше.
103105

104-
## EventMixin
106+
Вызов `super` ищет родительские методы в `[[HomeObject]].__proto__`, что означает `sayHiMixin.__proto__`, а не `User.__proto__`.
105107

106-
Сейчас давайте создадим примесь для реального случая.
108+
## EventMixin
107109

108-
Важная особенность при работе с объектами - это работа с событиями.
110+
А сейчас давайте создадим примесь, полезную в реальной жизни.
109111

110-
То есть, объект должен иметь метод для "генерации события", когда с ним происходит что-то важное, а другие объекты должны иметь возможность "слушать" такие события.
112+
Многие объекты в браузерной разработке (и не только) обладают важной способностью - они могут работать с событиями. События - это способ передачи информации всем, кто в ней заинтересован. Давайте создадим примесь, которая позволит легко добавлять функционал по работе с событиями любым классам/объектам.
111113

112-
Событие должно иметь имя и, опционально, какие-то дополнительные данные, ассоциированные с ним.
114+
- Примесь добавит метод `.trigger(name, [data])` для генерации события. Аргумент `name` - это имя события, за которым следует опциональный аргумент `data`.
115+
- Также будет добавлен метод `.on(name, handler)`, который назначает обработчик для события с заданным именем. Обработчик будет вызван, когда событие произойдёт.
116+
- ...и метод `.off(name, handler)`, который удаляет обработчик указанного события.
113117

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

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

118-
События — это способ "поделиться информацией" со всеми, кто этого захочет. Они могут быть полезны в любом классе, поэтому давайте сделаем для них пример:
122+
Рассмотрим это всё на примере:
119123

120124
```js run
121125
let eventMixin = {
122126
/**
123-
* Подпишемся на событие, используя:
127+
* Подписаться на событие, использование:
124128
* menu.on('select', function(item) { ... }
125129
*/
126130
on(eventName, handler) {
@@ -132,7 +136,7 @@ let eventMixin = {
132136
},
133137

134138
/**
135-
* Отменим подписку, используя:
139+
* Отменить подписку, использование:
136140
* menu.off('select', handler)
137141
*/
138142
off(eventName, handler) {
@@ -146,7 +150,7 @@ let eventMixin = {
146150
},
147151

148152
/**
149-
* Запустим событие и добавим к нему данные
153+
* Сгенерировать событие с указанным именем и данными
150154
* this.trigger('select', data1, data2);
151155
*/
152156
trigger(eventName, ...args) {
@@ -160,13 +164,13 @@ let eventMixin = {
160164
};
161165
```
162166

163-
Итак, у нас 3 метода:
167+
Итак, у нас есть 3 метода:
164168

165-
1. `.on(eventName, handler)` -- назначили функцию `handler`, чтобы обработать событие с заданным именем. Храним обработчики в свойстве `_eventHandlers`.
169+
1. `.on(eventName, handler)` -- назначает функцию `handler`, чтобы обработать событие с заданным именем. Обработчики хранятся в свойстве `_eventHandlers`, представляющим собой объект, в котором имя события является ключом, а массив обработчиков - значением.
166170

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

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

171175
Использование:
172176

@@ -191,9 +195,9 @@ menu.on("select", value => alert(`Выбранное значение: ${value}`
191195
menu.choose("123"); // выбранное значение
192196
```
193197

194-
Если у нас есть код, заинтересованный в событии "select", то мы можем привязать его с помощью `menu.on(...)`.
198+
Если у нас есть код, заинтересованный в событии "select", то он может подписаться на него с помощью `menu.on(...)`.
195199

196-
И `eventMixin` может добавить такое поведение в любой класс без вмешательства в цепочку наследования.
200+
И `eventMixin` позволяет легко добавить такое поведение в любой класс без вмешательства в цепочку наследования.
197201

198202
## Итого
199203

1-js/09-classes/07-mixins/head.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
let eventMixin = {
33

44
/**
5-
* Подпишемся на событие, используя:
6-
* menu.on('select', function(item) { ... }
5+
* Подписаться на событие, использование:
6+
* menu.on('select', function(item) { ... }
77
*/
88
on(eventName, handler) {
99
if (!this._eventHandlers) this._eventHandlers = {};
@@ -14,8 +14,8 @@
1414
},
1515

1616
/**
17-
* Отменим подписку, используя:
18-
* menu.off('select', handler)
17+
* Отменить подписку, использование:
18+
* menu.off('select', handler)
1919
*/
2020
off(eventName, handler) {
2121
let handlers = this._eventHandlers && this._eventHandlers[eventName];
@@ -28,8 +28,8 @@
2828
},
2929

3030
/**
31-
* Запустим событие и добавим к нему данные
32-
* this.trigger('select', data1, data2);
31+
* Сгенерировать событие с указанным именем и данными
32+
* this.trigger('select', data1, data2);
3333
*/
3434
trigger(eventName, ...args) {
3535
if (!this._eventHandlers || !this._eventHandlers[eventName]) {

0 commit comments

Comments
 (0)