diff --git a/1-js/09-classes/07-mixins/article.md b/1-js/09-classes/07-mixins/article.md index 526b832ef..debdaf017 100644 --- a/1-js/09-classes/07-mixins/article.md +++ b/1-js/09-classes/07-mixins/article.md @@ -1,22 +1,21 @@ # Mixins -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. +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. -But sometimes that feels limiting. For instance, we have a class `StreetSweeper` and a class `Bicycle`, and want to make their mix: a `StreetSweepingBicycle`. +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`; -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. +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. -There's a concept that can help here, called "mixins". +Existe um conceito que pode ajudar aqui, chamado "mixins". -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. +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. -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. +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. +## Um exemplo de mixin -## A mixin example +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. -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. - -For instance here the mixin `sayHiMixin` is used to add some "speech" for `User`: +Por exemplo, aqui onde o mixin `sayHiMixin` é usado para adicionar alguma "fala" para `User`: ```js run *!* @@ -32,7 +31,7 @@ let sayHiMixin = { }; *!* -// usage: +// Utilização: */!* class User { constructor(name) { @@ -40,14 +39,14 @@ class User { } } -// copy the methods +// copia os métodos Object.assign(User.prototype, sayHiMixin); -// now User can say hi +// agora User pode dizer oi new User("Dude").sayHi(); // Hello Dude! ``` -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: +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: ```js class User extends Person { @@ -57,9 +56,9 @@ class User extends Person { Object.assign(User.prototype, sayHiMixin); ``` -Mixins can make use of inheritance inside themselves. +Mixins usar herança dentro deles mesmos. -For instance, here `sayHiMixin` inherits from `sayMixin`: +Por exemplo, aqui `sayHiMixin` herda de `sayMixin`: ```js run let sayMixin = { @@ -69,11 +68,11 @@ let sayMixin = { }; let sayHiMixin = { - __proto__: sayMixin, // (or we could use Object.setPrototypeOf to set the prototype here) + __proto__: sayMixin, // (ou poderíamos usar Object.setPrototypeOf para definir o prototype aqui) sayHi() { *!* - // call parent method + // chama o método pai */!* super.say(`Hello ${this.name}`); // (*) }, @@ -88,43 +87,47 @@ class User { } } -// copy the methods +// copia os métodos Object.assign(User.prototype, sayHiMixin); -// now User can say hi +// agora User pode dizer oi new User("Dude").sayHi(); // Hello Dude! ``` -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. -Here's the diagram (see the right part): +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. + +Aqui o diagrama (veja a parte direita): ![](mixin-inheritance.svg) -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. +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. + -As `super` looks for parent methods in `[[HomeObject]].[[Prototype]]`, that means it searches `sayHiMixin.[[Prototype]]`. +Como `super` procura por métodos pais em `[[HomeObject]].[[Prototype]]`, isso significa que procura `sayHiMixin.[[Prototype]]`. ## EventMixin -Now let's make a mixin for real life. +Vamos criar um mixin para a vida real. -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. +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. -- 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. -- 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. -- ...And the method `.off(name, handler)` that removes the `handler` listener. +- 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. -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. +- 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` -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. +- ...E o método `.off(name, handler)` que remove o listener `handler`. -Here's the code: +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. + +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. + +Aqui está o código: ```js run let eventMixin = { /** - * Subscribe to event, usage: + * Se inscreve ao evento, utilização: * menu.on('select', function(item) { ... } */ on(eventName, handler) { @@ -136,7 +139,7 @@ let eventMixin = { }, /** - * Cancel the subscription, usage: + * Cancela a inscrição, utilização: * menu.off('select', handler) */ off(eventName, handler) { @@ -150,59 +153,60 @@ let eventMixin = { }, /** - * Generate an event with the given name and data + * Gera o evento e anexa os dados a ele * this.trigger('select', data1, data2); */ trigger(eventName, ...args) { if (!this._eventHandlers?.[eventName]) { - return; // no handlers for that event name + return; // sem manipuladores (handlers) para esse nome de evento } - // call the handlers + // chama o manipulador de eventos (handler) this._eventHandlers[eventName].forEach(handler => handler.apply(this, args)); } }; ``` +- `.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. + +- `.off(eventName, handler)` -- remove a função da lista de manipuladores de evento. -- `.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. -- `.off(eventName, handler)` -- removes the function from the handlers list. -- `.trigger(eventName, ...args)` -- generates the event: all handlers from `_eventHandlers[eventName]` are called, with a list of arguments `...args`. +- `.trigger(eventName, ...args)` -- gera o evento: todos os manipuladores de eventos de `_eventHandlers[eventName]` são chamados, com a lista de argumentos `...args`. -Usage: +Utilização: ```js run -// Make a class +// Cria uma classe class Menu { choose(value) { this.trigger("select", value); } } -// Add the mixin with event-related methods +// Adiciona o mixin com os métodos relacionados aos eventos. Object.assign(Menu.prototype, eventMixin); let menu = new Menu(); -// add a handler, to be called on selection: +// adiciona um manipulador de eventos, para ser chamado na seleção: *!* menu.on("select", value => alert(`Value selected: ${value}`)); */!* -// triggers the event => the handler above runs and shows: +// dispara o evento => o manipulador de evento acima executa e mostra: // Value selected: 123 menu.choose("123"); ``` -Now, if we'd like any code to react to a menu selection, we can listen for it with `menu.on(...)`. +Agora, se quisermos que qualquer código reaja á uma seleção de menu, podemos ouvir com `menu.on(...)`; -And `eventMixin` mixin makes it easy to add such behavior to as many classes as we'd like, without interfering with the inheritance chain. +E o mixin `eventMixin` facilita a adição do tal comportamento para tantas classes quanto quisermos, sem interferir na cadeia de herança. -## Summary +## Conclusão -*Mixin* -- is a generic object-oriented programming term: a class that contains methods for other classes. +*Mixin* -- é um termo genérico de programação orientada a objetos: uma classe que contém métodos para outras classes. -Some other languages allow multiple inheritance. JavaScript does not support multiple inheritance, but mixins can be implemented by copying methods into prototype. +Algumas outras linguagens permitem herança múltipla. JavaScript não suporta herança múltipla, porém os mixins podem ser implementados copiando métodos para prototype. -We can use mixins as a way to augment a class by adding multiple behaviors, like event-handling as we have seen above. +Podemos usar mixins como uma maneira de incrementar uma classe adicionando múltiplos comportamentos, como manipulação de eventos como vimos acima. -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. +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. diff --git a/1-js/09-classes/07-mixins/head.html b/1-js/09-classes/07-mixins/head.html index 20e3a6354..eecc59c64 100644 --- a/1-js/09-classes/07-mixins/head.html +++ b/1-js/09-classes/07-mixins/head.html @@ -2,7 +2,7 @@ let eventMixin = { /** - * Subscribe to event, usage: + * Se inscreve ao evento, utilização: * menu.on('select', function(item) { ... } */ on(eventName, handler) { @@ -14,7 +14,7 @@ }, /** - * Cancel the subscription, usage: + * Cancela a inscrição, utilização: * menu.off('select', handler) */ off(eventName, handler) { @@ -28,15 +28,15 @@ }, /** - * Generate the event and attach the data to it + * Gera o evento e anexa os dados a ele * this.trigger('select', data1, data2); */ trigger(eventName, ...args) { if (!this._eventHandlers || !this._eventHandlers[eventName]) { - return; // no handlers for that event name + return; // // sem manipuladores (handlers) para esse nome de evento } - // call the handlers + // chama o manipulador de eventos (handler) this._eventHandlers[eventName].forEach(handler => handler.apply(this, args)); } };