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/07-mixins/article.md
+31-38Lines changed: 31 additions & 38 deletions
Original file line number
Diff line number
Diff line change
@@ -1,35 +1,34 @@
1
1
# Mixins
2
2
3
-
Em JavaScript, só podemos herdar de um único objeto. Pode existir apenas um único `[[Prototype]]` para um objeto. E uma classe pode estender apenas uma outra classe.
3
+
Em JavaScript, só se pode herdar de um único objeto. Pode apenas existir um único `[[Prototype]]` para um objeto. E uma classe pode estender apenas uma outra classe.
4
4
5
5
Porém, algumas vezes isso parece limitante. Por exemplo, temos uma classe `StreetSweeper` e uma classe `Bicycle`, e queremos fazer uma mistura delas: uma classe `StreetSweepingBicycle`;
6
6
7
7
Ou temos uma classe `User` e uma classe `EventEmitter` que implementa a geração de eventos, e gostaríamos de adicionar a funcionalidade de `EventEmitter` à `User`, para que nossos usuários possam emitir eventos.
8
8
9
-
Existe um conceito que pode ajudar aqui, chamado "mixins".
9
+
Existe um conceito que nos pode ajudar aqui, chamado "mixins".
10
10
11
11
Como definido no Wikipedia, um [mixin](https://en.wikipedia.org/wiki/Mixin) é uma classe contendo métodos que podem ser usados por outras classes sem a necessidade de herdar dela.
12
12
13
-
Em outras palavras, um *mixin* fornece métodos que implementam um determinado comportamento, mas não o utilizamos sozinho, utilizamos ele para adicionar o comportamento a outras classes.
13
+
Em outras palavras, um *mixin* fornece métodos que implementam um determinado comportamento, mas não é utilizado sozinho, nós o utilizamos para adicionar o comportamento a outras classes.
14
+
14
15
## Um exemplo de mixin
15
16
16
-
A maneira mais simples de implementar um mixin em JavaScript é criando um objeto com métodos úteis, para que possamos facilmente mesclá-los em um prototype de qualquer classe.
17
+
A maneira mais simples de implementar um mixin em JavaScript é criando um objeto com métodos úteis, para que possamos facilmente mesclá-los em um prototype de outra classe.
17
18
18
-
Por exemplo, aqui onde o mixin `sayHiMixin` é usado para adicionar alguma "fala" para `User`:
19
+
Por exemplo, aqui o mixin `sayHiMixin` é usado para adicionar alguma "fala" para `User`:
19
20
20
21
```js run
21
22
*!*
22
23
// mixin
23
24
*/!*
24
25
let sayHiMixin = {
25
26
sayHi() {
26
-
alert(`Hello${this.name}`);
27
+
alert(`Olá${this.name}`);
27
28
},
28
29
sayBye() {
29
-
alert(`Bye${this.name}`);
30
+
alert(`Adeus${this.name}`);
30
31
}
31
-
};
32
-
33
32
*!*
34
33
// Utilização:
35
34
*/!*
@@ -43,10 +42,10 @@ class User {
43
42
Object.assign(User.prototype, sayHiMixin);
44
43
45
44
// agora User pode dizer oi
46
-
newUser("Dude").sayHi(); //Hello Dude!
45
+
newUser("Dude").sayHi(); //Olá Dude!
47
46
```
48
47
49
-
Não existe herança, mas uma simples cópia de método. Portanto, `User` pode herdar de uma outra classe e também incluir o mixin para "misturar" os métodos adicionais, assim:
48
+
Não existe herança, mas uma simples cópia de métodos. Portanto, `User` pode herdar de outra classe e também incluir o mixin para "misturar" (mix-in) os métodos adicionais, assim:
50
49
51
50
```js
52
51
classUserextendsPerson {
@@ -56,7 +55,7 @@ class User extends Person {
56
55
Object.assign(User.prototype, sayHiMixin);
57
56
```
58
57
59
-
Mixins usar herança dentro deles mesmos.
58
+
Mixins podem usar herança dentro deles mesmos.
60
59
61
60
Por exemplo, aqui `sayHiMixin` herda de `sayMixin`:
62
61
@@ -74,10 +73,10 @@ let sayHiMixin = {
74
73
*!*
75
74
// chama o método pai
76
75
*/!*
77
-
super.say(`Hello${this.name}`); // (*)
76
+
super.say(`Olá${this.name}`); // (*)
78
77
},
79
78
sayBye() {
80
-
super.say(`Bye${this.name}`); // (*)
79
+
super.say(`Adeus${this.name}`); // (*)
81
80
}
82
81
};
83
82
@@ -86,41 +85,36 @@ class User {
86
85
this.name= name;
87
86
}
88
87
}
89
-
90
88
// copia os métodos
91
89
Object.assign(User.prototype, sayHiMixin);
92
90
93
91
// agora User pode dizer oi
94
-
newUser("Dude").sayHi(); //Hello Dude!
92
+
newUser("Dude").sayHi(); //Olá Dude!
95
93
```
96
94
95
+
Observe que a chamada do método pai `super.say()` por `sayHiMixin` (nas linhas marcadas com `(*)`) procura pelo método no prototype desse mixin, não na classe.
97
96
98
-
Observe que a chamada do método pai `super.say()` por `sayHiMixin` (las linhas marcadas com `(*)`) procura pelo método no prototype desse mixin, não na classe.
99
-
100
-
Aqui o diagrama (veja a parte direita):
97
+
Aqui está o diagrama (veja a parte direita):
101
98
102
99

103
100
104
-
Isso porque os métodos `sayHi` e `sayBye` foram inicialmente criados em `sayHiMixin`. Portanto, mesmo que tenha sido copiados, suas propriedades internas `[[HomeObject]]`referencia a `sayHiMixin`, como mostrado na figura acima.
101
+
Isso porque os métodos `sayHi` e `sayBye` foram inicialmente criados em `sayHiMixin`. Portanto, mesmo que tenham sido copiados, suas propriedades internas `[[HomeObject]]`referenciam a `sayHiMixin`, como mostrado na figura acima.
105
102
106
-
107
-
Como `super` procura por métodos pais em `[[HomeObject]].[[Prototype]]`, isso significa que procura `sayHiMixin.[[Prototype]]`.
103
+
Como `super` procura por métodos pais em `[[HomeObject]].[[Prototype]]`, isso significa que procura em `sayHiMixin.[[Prototype]]`.
108
104
109
105
## EventMixin
110
106
111
107
Vamos criar um mixin para a vida real.
112
108
113
-
Uma característica importante de muitos objetos do navegador (por exemplo) é que eles podem gerar eventos. Eventos são uma ótima maneira de "transmitir informação" para qualquer um que a quiser. Então, vamos criar um mixin que nos permita adicionar facilmente funções relacionadas a eventos a qualquer classe/objeto.
114
-
115
-
- O mixin vai fornecer um método `.trigger(name, [...data])` para "gerar um evento" quando algo importante acontecer com ele. O argumento `name` é o nome do evento, opcionalmente seguido de argumentos adicionais com dados do evento.
109
+
Uma característica importante de muitos objetos do navegador (por exemplo) é que eles podem gerar eventos. Eventos são uma ótima maneira de "transmitir informação" para qualquer um que a quiser. Então, vamos criar um mixin que nos permita facilmente adicionar funções relacionadas a eventos a qualquer classe/objeto.
116
110
117
-
-Além do método `.on(name, handler)`que adiciona a função `handler` como ouvinte de eventos com o dado nome. Ele será chamado quando um evento com o dado `name` disparar, e irá obter os argumentos da chamada de `.trigger`
118
-
119
-
- ...E o método `.off(name, handler)` que remove o listener`handler`.
111
+
- O mixin vai fornecer um método `.trigger(name, [...data])`para "gerar um evento" quando algo importante acontecer com ele. O argumento `name` é o nome do evento, e é opcionalmente seguido de argumentos provendo dados do evento.
112
+
- E também o método `.on(name, handler)` que adiciona a função `handler` como ouvinte de eventos com o dado nome. Ela será chamada quando um evento com o dado `name` disparar, e irá obter os argumentos da chamada de `.trigger`
113
+
- ...E o método `.off(name, handler)` que remove o ouvinte`handler`.
120
114
121
115
Após adicionar o mixin, um objeto `user` será capaz de gerar um evento `"login"` quando o visitante fizer login. Um outro objeto, digamos, `calendar` pode querer ouvir por tais eventos para carregar o calendário para a pessoa logada.
122
116
123
-
Ou, um `menu` pode gerar o evento `"select" quando um item do menu for selecionado`, e outros objetos podem atribuir manipuladores (handlers) para reagir aquele evento.
117
+
Ou, um `menu` pode gerar o evento `"select"` quando um item do menu for selecionado`, e outros objetos podem atribuir manipuladores (handlers) para reagir àqueleevento. E assim por diante.
124
118
125
119
Aqui está o código:
126
120
@@ -153,24 +147,23 @@ let eventMixin = {
153
147
},
154
148
155
149
/**
156
-
* Gera o evento e anexa os dados a ele
150
+
* Gera um evento com o nome e dados providenciados
157
151
* this.trigger('select', data1, data2);
158
152
*/
159
153
trigger(eventName, ...args) {
160
154
if (!this._eventHandlers?.[eventName]) {
161
155
return; // sem manipuladores (handlers) para esse nome de evento
- `.on(eventName, handler)` -- atribui a função `handler` para executar quando o evento com aquele nome ocorre. Tecnicamente, existe uma propriedade `_eventHandlers` que armazena um array de manipuladores de evento para cada nome de evento, e apenas o adiciona a lista.
171
164
165
+
-`.on(eventName, handler)`-- atribui a função `handler` para ser executada quando o evento com aquele nome ocorre. Tecnicamente, existe uma propriedade `_eventHandlers` que armazena um array de manipuladores de evento para cada nome de evento, e o método apenas adiciona o manipulador à lista.
172
166
-`.off(eventName, handler)`-- remove a função da lista de manipuladores de evento.
173
-
174
167
-`.trigger(eventName, ...args)`-- gera o evento: todos os manipuladores de eventos de `_eventHandlers[eventName]` são chamados, com a lista de argumentos `...args`.
175
168
176
169
Utilização:
@@ -189,15 +182,15 @@ let menu = new Menu();
189
182
190
183
// adiciona um manipulador de eventos, para ser chamado na seleção:
menu.on("select", value => alert(`Valor selecionado: ${value}`));
193
186
*/!*
194
187
195
-
// dispara o evento => o manipulador de evento acima executa e mostra:
196
-
//Value selected: 123
188
+
// dispara o evento => o manipulador de evento acima é executado e mostra:
189
+
// Valor selecionado: 123
197
190
menu.choose("123");
198
191
```
199
192
200
-
Agora, se quisermos que qualquer código reaja á uma seleção de menu, podemos ouvir com `menu.on(...)`;
193
+
Agora, se quisermos que qualquer código reaja a uma seleção do menu, podemos ouvir com `menu.on(...)`.
201
194
202
195
E o mixin `eventMixin` facilita a adição do tal comportamento para tantas classes quanto quisermos, sem interferir na cadeia de herança.
203
196
@@ -209,4 +202,4 @@ Algumas outras linguagens permitem herança múltipla. JavaScript não suporta h
209
202
210
203
Podemos usar mixins como uma maneira de incrementar uma classe adicionando múltiplos comportamentos, como manipulação de eventos como vimos acima.
211
204
212
-
Mixins podem se tornar um ponto de conflito se eles acidentalmente sobrescreverem métodos existentes da classe. Então geralmente deve-se pensar bem sobre a nomenclatura de um mixin, para minimizar a probabilidade disso acontecer.
205
+
Mixins podem se tornar num ponto de conflito se eles acidentalmente sobrescreverem métodos existentes naclasse. Então geralmente deve-se pensar bem sobre a nomenclatura dos métodos de um mixin, para minimizar a probabilidade disso acontecer.
0 commit comments