Skip to content

Commit c874622

Browse files
authored
Merge pull request #188 from otmon76/1.9.7
Mixins
2 parents 76735fd + a7ae568 commit c874622

File tree

3 files changed

+126
-127
lines changed

3 files changed

+126
-127
lines changed

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

Lines changed: 102 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,208 +1,208 @@
1-
# Mixins
1+
# Mixiny
22

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.
3+
V JavaScriptu můžeme dědit jen z jednoho objektu. Objekt může mít jen jeden `[[Prototype]]` a třída může rozšiřovat pouze jednu jinou třídu.
44

5-
But sometimes that feels limiting. For instance, we have a class `StreetSweeper` and a class `Bicycle`, and want to make their mix: a `StreetSweepingBicycle`.
5+
To se však někdy může zdát omezující. Máme například třídu `ZametačUlic` a třídu `Bicykl` a chtěli bychom vytvořit jejich směs: `ZametacíBicykl`.
66

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.
7+
Nebo máme třídu `Uživatel` a třídu `GenerátorUdálostí`, která implementuje generování událostí, a rádi bychom přidali funkcionalitu třídy `GenerátorUdálostí` do třídy `Uživatel`, aby naši uživatelé mohli generovat události.
88

9-
There's a concept that can help here, called "mixins".
9+
Koncept, který nám s tím pomůže, existuje a nazývá se „mixiny“.
1010

11-
As defined in Wikipedia, a [mixin](https://en.wikipedia.org/wiki/Mixin) is a class containing methods that can be used by other classes without a need to inherit from it.
11+
Jak je definováno ve Wikipedii, [mixin](https://cs.wikipedia.org/wiki/Mixin) je třída obsahující metody, které mohou být používány v jiných třídách, aniž by z ní tyto třídy musely být zděděny.
1212

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.
13+
Jinými slovy, *mixin* poskytuje metody, které implementují určité chování, ale nepoužíváme ho samostatně, nýbrž přidáváme jeho chování do jiných tříd.
1414

15-
## A mixin example
15+
## Příklad mixinu
1616

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.
17+
Nejjednodušší způsob, jak implementovat mixin v JavaScriptu, je vytvořit objekt s užitečnými metodami, abychom je mohli snadno připojit do prototypu libovolné třídy.
1818

19-
For instance here the mixin `sayHiMixin` is used to add some "speech" for `User`:
19+
Například zde je použit mixin `mixinŘekniAhoj`, aby do třídy `Uživatel` přidal nějaké „mluvení“:
2020

2121
```js run
2222
*!*
2323
// mixin
2424
*/!*
25-
let sayHiMixin = {
26-
sayHi() {
27-
alert(`Hello ${this.name}`);
25+
let mixinŘekniAhoj = {
26+
řekniAhoj() {
27+
alert(`Ahoj ${this.jméno}`);
2828
},
29-
sayBye() {
30-
alert(`Bye ${this.name}`);
29+
řekniNashle() {
30+
alert(`Nashle ${this.jméno}`);
3131
}
3232
};
3333

3434
*!*
35-
// usage:
35+
// použití:
3636
*/!*
37-
class User {
38-
constructor(name) {
39-
this.name = name;
37+
class Uživatel {
38+
constructor(jméno) {
39+
this.jméno = jméno;
4040
}
4141
}
4242

43-
// copy the methods
44-
Object.assign(User.prototype, sayHiMixin);
43+
// zkopírujeme metody
44+
Object.assign(Uživatel.prototype, mixinŘekniAhoj);
4545

46-
// now User can say hi
47-
new User("Dude").sayHi(); // Hello Dude!
46+
// nyní Uživatel může říci ahoj
47+
new Uživatel("Jan").řekniAhoj(); // Ahoj Jan
4848
```
4949

50-
There's no inheritance, but a simple method copying. So `User` may inherit from another class and also include the mixin to "mix-in" the additional methods, like this:
50+
Není tady žádná dědičnost, ale jen prosté kopírování metod. `Uživatel` tedy může dědit z jiné třídy a současně zahrnout mixin, aby „přimíchal“ („mix-in“) další metody, například:
5151

5252
```js
53-
class User extends Person {
53+
class Uživatel extends Osoba {
5454
// ...
5555
}
5656

57-
Object.assign(User.prototype, sayHiMixin);
57+
Object.assign(Uživatel.prototype, mixinŘekniAhoj);
5858
```
5959

60-
Mixins can make use of inheritance inside themselves.
60+
Mixiny mohou využívat dědičnost mezi sebou.
6161

62-
For instance, here `sayHiMixin` inherits from `sayMixin`:
62+
Například zde `mixinŘekniAhoj` dědí z `mixinŘekni`:
6363

6464
```js run
65-
let sayMixin = {
66-
say(phrase) {
67-
alert(phrase);
65+
let mixinŘekni = {
66+
řekni(věta) {
67+
alert(věta);
6868
}
6969
};
7070

71-
let sayHiMixin = {
72-
__proto__: sayMixin, // (or we could use Object.setPrototypeOf to set the prototype here)
71+
let mixinŘekniAhoj = {
72+
__proto__: mixinŘekni, // (nebo můžeme k nastavení prototypu použít Object.setPrototypeOf)
7373

74-
sayHi() {
74+
řekniAhoj() {
7575
*!*
76-
// call parent method
76+
// volání rodičovské metody
7777
*/!*
78-
super.say(`Hello ${this.name}`); // (*)
78+
super.řekni(`Ahoj ${this.jméno}`); // (*)
7979
},
80-
sayBye() {
81-
super.say(`Bye ${this.name}`); // (*)
80+
řekniNashle() {
81+
super.řekni(`Nashle ${this.jméno}`); // (*)
8282
}
8383
};
8484

85-
class User {
86-
constructor(name) {
87-
this.name = name;
85+
class Uživatel {
86+
constructor(jméno) {
87+
this.jméno = jméno;
8888
}
8989
}
9090

91-
// copy the methods
92-
Object.assign(User.prototype, sayHiMixin);
91+
// zkopírujeme metody
92+
Object.assign(Uživatel.prototype, mixinŘekniAhoj);
9393

94-
// now User can say hi
95-
new User("Dude").sayHi(); // Hello Dude!
94+
// nyní Uživatel může říci ahoj
95+
new Uživatel("Jan").řekniAhoj(); // Ahoj Jan
9696
```
9797

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.
98+
Prosíme všimněte si, že volání rodičovské metody `super.řekni()` z `mixinŘekniAhoj` (na řádcích označených `(*)`) hledá metodu v prototypu onoho mixinu, ne této třídy.
9999

100-
Here's the diagram (see the right part):
100+
Zde je diagram (viz pravou část):
101101

102102
![](mixin-inheritance.svg)
103103

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 in the picture above.
104+
Je to proto, že metody `řekniAhoj` a `řekniNashle` byly původně vytvořeny v `mixinŘekniAhoj`. I když jsou tedy zkopírovány, jejich interní vlastnost `[[HomeObject]]` se odkazuje na `mixinŘekniAhoj`, jak je vidět na uvedeném obrázku.
105105

106-
As `super` looks for parent methods in `[[HomeObject]].[[Prototype]]`, that means it searches `sayHiMixin.[[Prototype]]`.
106+
Když `super` hledá rodičovské metody v `[[HomeObject]].[[Prototype]]`, znamená to, že prohledává `mixinŘekniAhoj.[[Prototype]]`.
107107

108-
## EventMixin
108+
## MixinUdálosti
109109

110-
Now let's make a mixin for real life.
110+
Vytvořme nyní mixin pro skutečný život.
111111

112-
An important feature of many browser objects (for instance) is that they can generate events. Events are a great way to "broadcast information" to anyone who wants it. So let's make a mixin that allows us to easily add event-related functions to any class/object.
112+
Důležitou vlastností mnoha objektů prohlížeče (například) je, že mohou generovat události. Události jsou skvělý způsob, jak „vysílat informaci“ každému, kdo ji chce. Vytvořme tedy mixin, který nám umožní snadno přidat funkce vztažené k události do jakékoli třídy nebo objektu.
113113

114-
- The mixin will provide a method `.trigger(name, [...data])` to "generate an event" when something important happens to it. The `name` argument is a name of the event, optionally followed by additional arguments with event data.
115-
- Also the method `.on(name, handler)` that adds `handler` function as the listener to events with the given name. It will be called when an event with the given `name` triggers, and get the arguments from the `.trigger` call.
116-
- ...And the method `.off(name, handler)` that removes the `handler` listener.
114+
- Mixin bude poskytovat metodu `.spusť(název, [...data])`, která bude „generovat událost“, když se stane něco důležitého. Argument `název` je název události, za nímž mohou následovat další argumenty s daty události.
115+
- Dále metodu `.zapni(název, handler)`, která přidá funkci `handler` jako posluchače událostí se zadaným názvem. Funkce `handler` bude volána, když se spustí událost se zadaným názvem `název`, a převezme argumenty z volání `.spusť`.
116+
- ...A metodu `.vypni(název, handler)`, která odstraní posluchače `handler`.
117117

118-
After adding the mixin, an object `user` will be able to generate an event `"login"` when the visitor logs in. And another object, say, `calendar` may want to listen for such events to load the calendar for the logged-in person.
118+
Po přidání mixinu bude objekt `uživatel` moci generovat událost `"přihlášen"`, když se uživatel přihlásí. A jiný objekt, třeba `kalendář`, bude moci takovým událostem naslouchat, aby pak načetl kalendář pro přihlášenou osobu.
119119

120-
Or, a `menu` can generate the event `"select"` when a menu item is selected, and other objects may assign handlers to react on that event. And so on.
120+
Nebo `menu` může generovat událost `"vybrán"`, když je vybrán jeho prvek, a jiné objekty mohou přiřazovat handlery, které budou na tuto událost reagovat. A tak dále.
121121

122-
Here's the code:
122+
Zde je kód:
123123

124124
```js run
125-
let eventMixin = {
125+
let mixinUdálosti = {
126126
/**
127-
* Subscribe to event, usage:
128-
* menu.on('select', function(item) { ... }
127+
* Přihlášení k naslouchání události, použití:
128+
* menu.zapni('vybrán', function(prvek) { ... })
129129
*/
130-
on(eventName, handler) {
131-
if (!this._eventHandlers) this._eventHandlers = {};
132-
if (!this._eventHandlers[eventName]) {
133-
this._eventHandlers[eventName] = [];
130+
zapni(názevUdálosti, handler) {
131+
if (!this._handleryUdálostí) this._handleryUdálostí = {};
132+
if (!this._handleryUdálostí[názevUdálosti]) {
133+
this._handleryUdálostí[názevUdálosti] = [];
134134
}
135-
this._eventHandlers[eventName].push(handler);
135+
this._handleryUdálostí[názevUdálosti].push(handler);
136136
},
137137

138138
/**
139-
* Cancel the subscription, usage:
140-
* menu.off('select', handler)
139+
* Odhlášení z naslouchání události, použití:
140+
* menu.vypni('vybrán', handler)
141141
*/
142-
off(eventName, handler) {
143-
let handlers = this._eventHandlers?.[eventName];
144-
if (!handlers) return;
145-
for (let i = 0; i < handlers.length; i++) {
146-
if (handlers[i] === handler) {
147-
handlers.splice(i--, 1);
142+
vypni(názevUdálosti, handler) {
143+
let handlery = this._handleryUdálostí?.[názevUdálosti];
144+
if (!handlery) return;
145+
for (let i = 0; i < handlery.length; i++) {
146+
if (handlery[i] === handler) {
147+
handlery.splice(i--, 1);
148148
}
149149
}
150150
},
151151

152152
/**
153-
* Generate an event with the given name and data
154-
* this.trigger('select', data1, data2);
153+
* Generování události se zadaným názvem a daty
154+
* this.spusť('vybrán', data1, data2);
155155
*/
156-
trigger(eventName, ...args) {
157-
if (!this._eventHandlers?.[eventName]) {
158-
return; // no handlers for that event name
156+
spusť(názevUdálosti, ...argumenty) {
157+
if (!this._handleryUdálostí?.[názevUdálosti]) {
158+
return; // pro událost s tímto názvem nejsou žádné handlery
159159
}
160160

161-
// call the handlers
162-
this._eventHandlers[eventName].forEach(handler => handler.apply(this, args));
161+
// volání handlerů
162+
this._handleryUdálostí[názevUdálosti].forEach(handler => handler.apply(this, argumenty));
163163
}
164164
};
165165
```
166166
167167
168-
- `.on(eventName, handler)` -- assigns function `handler` to run when the event with that name occurs. Technically, there's an `_eventHandlers` property that stores an array of handlers for each event name, and it just adds it to the list.
169-
- `.off(eventName, handler)` -- removes the function from the handlers list.
170-
- `.trigger(eventName, ...args)` -- generates the event: all handlers from `_eventHandlers[eventName]` are called, with a list of arguments `...args`.
168+
- `.zapni(názevUdálosti, handler)` -- přiřadí funkci `handler`, která se má spustit vždy, když nastane událost s uvedeným názvem. Technicky je zde vlastnost `_handleryUdálostí`, do níž se ukládá pole handlerů pro každý název události, a funkce je prostě přidána do tohoto seznamu.
169+
- `.vypni(názevUdálosti, handler)` -- odstraní funkci ze seznamu handlerů.
170+
- `.spusť(názevUdálosti, ...argumenty)` -- generuje událost: všechny handlery z `_handleryUdálostí[názevUdálosti]` jsou volány se seznamem argumentů `...argumenty`.
171171
172-
Usage:
172+
Použití:
173173
174174
```js run
175-
// Make a class
175+
// Vytvoříme třídu
176176
class Menu {
177-
choose(value) {
178-
this.trigger("select", value);
177+
vyber(hodnota) {
178+
this.spusť("vybrán", hodnota);
179179
}
180180
}
181-
// Add the mixin with event-related methods
182-
Object.assign(Menu.prototype, eventMixin);
181+
// Přidáme mixin s metodami vztahujícími se k událostem
182+
Object.assign(Menu.prototype, mixinUdálosti);
183183

184184
let menu = new Menu();
185185

186-
// add a handler, to be called on selection:
186+
// přidáme handler, který bude volán při výběru:
187187
*!*
188-
menu.on("select", value => alert(`Value selected: ${value}`));
188+
menu.zapni("vybrán", hodnota => alert(`Vybrána hodnota: ${hodnota}`));
189189
*/!*
190190

191-
// triggers the event => the handler above runs and shows:
192-
// Value selected: 123
193-
menu.choose("123");
191+
// spustí událost => výše uvedený handler se spustí a zobrazí:
192+
// Vybrána hodnota: 123
193+
menu.vyber("123");
194194
```
195195
196-
Now, if we'd like any code to react to a menu selection, we can listen for it with `menu.on(...)`.
196+
Kdybychom nyní chtěli přidat jakýkoli kód, který bude reagovat na výběr z menu, můžeme mu naslouchat pomocí `menu.zapni(...)`.
197197
198-
And `eventMixin` mixin makes it easy to add such behavior to as many classes as we'd like, without interfering with the inheritance chain.
198+
A mixin `mixinUdálosti` usnadňuje přidání takového chování do tolika tříd, do kolika bychom chtěli, aniž bychom narušovali řetězec dědičnosti.
199199
200-
## Summary
200+
## Shrnutí
201201
202-
*Mixin* -- is a generic object-oriented programming term: a class that contains methods for other classes.
202+
*Mixin* -- je generický pojem objektově orientovaného programování: třída, která obsahuje metody pro jiné třídy.
203203
204-
Some other languages allow multiple inheritance. JavaScript does not support multiple inheritance, but mixins can be implemented by copying methods into prototype.
204+
Některé jiné jazyky umožňují vícenásobnou dědičnost. JavaScript ji nepodporuje, ale mixiny mohou být implementovány zkopírováním metod do prototypu.
205205
206-
We can use mixins as a way to augment a class by adding multiple behaviors, like event-handling as we have seen above.
206+
Mixiny můžeme používat jako způsob rozšiřování třídy přidáváním dalšího chování, například ošetřování událostí, jak jsme viděli výše.
207207
208-
Mixins may become a point of conflict if they accidentally overwrite existing class methods. So generally one should think well about the naming methods of a mixin, to minimize the probability of that happening.
208+
Mixiny se mohou stát příčinou konfliktu, jestliže náhodou přepíší již existující metody třídy. Obecně bychom si tedy měli dobře rozmyslet názvy metod v mixinu, abychom minimalizovali pravděpodobnost, že se tak stane.

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

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,42 @@
11
<script>
2-
let eventMixin = {
3-
2+
let mixinUdálosti = {
43
/**
5-
* Subscribe to event, usage:
6-
* menu.on('select', function(item) { ... }
4+
* Přihlášení k naslouchání události, použití:
5+
* menu.zapni('vybrán', function(prvek) { ... })
76
*/
8-
on(eventName, handler) {
9-
if (!this._eventHandlers) this._eventHandlers = {};
10-
if (!this._eventHandlers[eventName]) {
11-
this._eventHandlers[eventName] = [];
7+
zapni(názevUdálosti, handler) {
8+
if (!this._handleryUdálostí) this._handleryUdálostí = {};
9+
if (!this._handleryUdálostí[názevUdálosti]) {
10+
this._handleryUdálostí[názevUdálosti] = [];
1211
}
13-
this._eventHandlers[eventName].push(handler);
12+
this._handleryUdálostí[názevUdálosti].push(handler);
1413
},
1514

1615
/**
17-
* Cancel the subscription, usage:
18-
* menu.off('select', handler)
16+
* Odhlášení z naslouchání události, použití:
17+
* menu.vypni('vybrán', handler)
1918
*/
20-
off(eventName, handler) {
21-
let handlers = this._eventHandlers?.[eventName];
22-
if (!handlers) return;
23-
for(let i = 0; i < handlers.length; i++) {
24-
if (handlers[i] == handler) {
25-
handlers.splice(i--, 1);
19+
vypni(názevUdálosti, handler) {
20+
let handlery = this._handleryUdálostí?.[názevUdálosti];
21+
if (!handlery) return;
22+
for (let i = 0; i < handlery.length; i++) {
23+
if (handlery[i] === handler) {
24+
handlery.splice(i--, 1);
2625
}
2726
}
2827
},
2928

3029
/**
31-
* Generate the event and attach the data to it
32-
* this.trigger('select', data1, data2);
30+
* Generování události se zadaným názvem a daty
31+
* this.spusť('vybrán', data1, data2);
3332
*/
34-
trigger(eventName, ...args) {
35-
if (!this._eventHandlers || !this._eventHandlers[eventName]) {
36-
return; // no handlers for that event name
33+
spusť(názevUdálosti, ...argumenty) {
34+
if (!this._handleryUdálostí?.[názevUdálosti]) {
35+
return; // pro událost s tímto názvem nejsou žádné handlery
3736
}
3837

39-
// call the handlers
40-
this._eventHandlers[eventName].forEach(handler => handler.apply(this, args));
38+
// volání handlerů
39+
this._handleryUdálostí[názevUdálosti].forEach(handler => handler.apply(this, argumenty));
4140
}
4241
};
4342
</script>

0 commit comments

Comments
 (0)