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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
In JavaScriptwe 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.
En JavaScriptpodemos heredar de un solo objeto. Solo puede haber un`[[Prototype]]`para un objeto. Y una clase puede extender únicamente otra clase.
But sometimes that feels limiting. For instance, we have a class`StreetSweeper`and a class `Bicycle`,and want to make their mix: a `StreetSweepingBicycle`.
Pero a veces eso se siente restrictivo. Por ejemplo, tenemos una clase`StreetSweeper`y una clase `Bicycle`,y queremos hacer su combinación: un `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.
O tenemos una clase`User`y una clase `EventEmitter`que implementa la generación de eventos, y nos gustaría agregar la funcionalidad de`EventEmitter`a `User`,para que nuestros usuarios puedan emitir eventos.
There's a concept that can help here, called "mixins".
Hay un concepto que puede ayudar aquí, llamado "mixins".
As defined inWikipedia,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 se define enWikipedia,un [mixin](https://es.wikipedia.org/wiki/Mixin)es una clase que contiene métodos que pueden ser utilizados por otras clases sin necesidad de heredar de ella.
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.
En otras palabras, un *mixin*proporciona métodos que implementan cierto comportamiento, pero su uso no es exclusivo, lo usamos para agregar el comportamiento a otras clases.
##A mixin example
##Un ejemplo de mixin
The simplest way to implement amixinin JavaScriptis to make an object with useful methods, so that we can easily merge them into a prototype of any class.
La forma más sencilla de implementar unmixinen JavaScriptes hacer un objeto con métodos útiles, para que podamos combinarlos fácilmente en un prototipo de cualquier clase.
For instance here the mixin `sayHiMixin`is used to add some "speech" for `User`:
Por ejemplo, aquí el mixin `sayHiMixin`se usa para agregar algo de "diálogo" a `User`:
```js run
*!*
// mixin
*/!*
let sayHiMixin = {
sayHi() {
alert(`Hello ${this.name}`);
alert(`Hola ${this.name}`);
},
sayBye() {
alert(`Bye ${this.name}`);
alert(`Adios ${this.name}`);
}
};
*!*
//usage:
//uso:
*/!*
class User {
constructor(name) {
this.name = name;
}
}
//copy the methods
//copia los métodos
Object.assign(User.prototype, sayHiMixin);
//nowUsercan say hi
new User("Dude").sayHi(); //Hello Dude!
//Ahora elUserpuede decir hola
new User("tío").sayHi(); //Hola tío!
```
There's no inheritance, but a simplemethod copying. So `User`may inherit from another class and also include the mixinto "mix-in" the additional methods, like this:
No hay herencia, sino un simplemétodo de copia. Entonces, `User`puede heredar de otra clase y también incluir el mixinpara "mezclar" los métodos adicionales, como este:
```js
class User extends Person {
Expand All
@@ -57,9 +57,9 @@ class User extends Person {
Object.assign(User.prototype, sayHiMixin);
```
Mixins can make use of inheritance inside themselves.
Los mixins pueden hacer uso de la herencia dentro de sí mismos.
For instance, here `sayHiMixin`inherits from `sayMixin`:
Por ejemplo, aquí `sayHiMixin`hereda de `sayMixin`:
```js run
let sayMixin = {
Expand All
@@ -69,16 +69,16 @@ let sayMixin = {
};
let sayHiMixin = {
__proto__: sayMixin, // (or we could useObject.createto set the prototypehere)
__proto__: sayMixin, // (o podríamos usarObject.createpara configurar el prototypeaquí)
sayHi() {
*!*
//call parent method
//llama al método padre
*/!*
super.say(`Hello ${this.name}`); // (*)
super.say(`Hola ${this.name}`); // (*)
},
sayBye() {
super.say(`Bye ${this.name}`); // (*)
super.say(`Adios ${this.name}`); // (*)
}
};
Expand All
@@ -88,43 +88,43 @@ class User {
}
}
//copy the methods
//copia los métodos
Object.assign(User.prototype, sayHiMixin);
//nowUsercan say hi
new User("Dude").sayHi(); //Hello Dude!
// Userahora puede decir hola
new User("tío").sayHi(); //Hola tío!
```
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 thatmixin,not the class.
Ten en cuenta que la llamada al método padre `super.say()`de `sayHiMixin` (en las líneas etiquetadas con`(*)`)busca el método en el prototipo de esemixin,no en la clase.
Here's the diagram (see the right part):
Aquí está el diagrama (ver la parte derecha):

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.
Esto se debe a que los métodos`sayHi`y `sayBye`se crearon inicialmente en `sayHiMixin`.Entonces, a pesar de que se copiaron, su propiedad interna`[[[HomeObject]]`hace referencia a `sayHiMixin`,como se muestra en la imagen de arriba.
As `super`looks for parent methods in`[[HomeObject]].[[Prototype]]`,that means it searches `sayHiMixin.[[Prototype]]`,not `User.[[Prototype]]`.
Como `super`busca métodos primarios en`[[HomeObject]].[[Prototype]]`, significa que busca `sayHiMixin.[[Prototype]]`,no `User.[[Prototype]]`.
## EventMixin
Now let's make amixinfor real life.
Ahora hagamos unmixinpara la 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 mixinthat allows us to easily add event-related functions to any class/object.
Una característica importante de muchos objetos del navegador (por ejemplo) es que pueden generar eventos. Los eventos son una excelente manera de "transmitir información" a cualquiera que lo desee. Así que hagamos un mixinque nos permita agregar fácilmente funciones relacionadas con eventos a cualquier clase/objeto.
-The mixinwill 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 thelistenerto 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.
-El mixinproporcionará un método`.trigger(name, [...data])`para "generar un evento" cuando le ocurra algo importante. El argumento`name`es un nombre del evento, opcionalmente seguido de argumentos adicionales con datos del evento.
-También el método `.on(name, handler)`que agrega la función`handler`comolistenera eventos con el nombre dado. Se llamará cuando se desencadene un evento con el nombre `name`dado, y obtenga los argumentos de la llamada`.trigger`.
- ...Y el método `.off(name, handler)`que elimina el listener`handler`.
After adding themixin,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.
Después de agregar elmixin,un objeto `user`podrá generar un evento`"login"`cuando el visitante inicie sesión. Y otro objeto, por ejemplo, `calendar`puede querer escuchar dichos eventos para cargar el calendario para el persona registrada.
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.
O bien, un `menu`puede generar el evento `"seleccionar"`cuando se selecciona un elemento del menú, y otros objetos pueden asignar controladores para reaccionar ante ese evento. Y así.
Here's the code:
Aquí está el código:
```js run
let eventMixin = {
/**
*Subscribe to event, usage:
*Suscribe al evento, uso:
* menu.on('select', function(item) { ... }
*/
on(eventName, handler) {
Expand All
@@ -136,7 +136,7 @@ let eventMixin = {
},
/**
*Cancel the subscription, usage:
*Cancelar la suscripción, uso:
* menu.off('select', handler)
*/
off(eventName, handler) {
Expand All
@@ -150,12 +150,12 @@ let eventMixin = {
},
/**
*Generate an event with the given name and data
*Generar un evento con el nombre y los datos
* this.trigger('select', data1, data2);
*/
trigger(eventName, ...args) {
if (!this._eventHandlers || !this._eventHandlers[eventName]) {
return; // nohandlers for that event name
return; // nohay controladores para ese nombre de evento
}
// call the handlers
Expand All
@@ -165,44 +165,44 @@ let eventMixin = {
```
- `.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`.
- `.on(eventName, handler)`: asigna la función `handler`para que se ejecute cuando se produce el evento con ese nombre. Técnicamente, hay una propiedad`_eventHandlers`que almacena una matriz de controladores para cada nombre de evento, y simplemente la agrega a la lista.
- `.off(eventName, handler)` - elimina la función de la lista de controladores.
- `.trigger(eventName, ...args)` - genera el evento: se llama a todos los controladores de`_eventHandlers[eventName]`, con una lista de argumentos `...args`.
Usage:
Uso:
```js run
//Make a class
//Construir una clase
class Menu {
choose(value) {
this.trigger("select", value);
}
}
//Add the mixinwith event-related methods
//Agrega el mixincon métodos relacionados con eventos
Object.assign(Menu.prototype, eventMixin);
let menu = new Menu();
//add a handler, to be called on selection:
//agrega un controlador, que se llamará en la selección:
*!*
menu.on("select", value => alert(`Value selected: ${value}`));
menu.on("select", value => alert(`Valor seleccionado: ${value}`));
*/!*
//triggers the event =>the handler above runs and shows:
//Value selected: 123
//desencadena el evento =>el controlador anterior se ejecuta y muestra:
//Valor seleccionado: 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(...)`.
Ahora, si queremos que el código reaccione a una selección de menú, podemos escucharlo con `menu.on(...)`.
And `eventMixin` mixinmakes it easy to add such behavior to as many classes as we'd like, without interfering with the inheritance chain.
Y el mixinde `eventMixin` hace que sea fácil agregar ese comportamiento a tantas clases como queramos, sin interferir con la cadena de herencia.
##Summary
##Resumen
*Mixin* --is a generic object-oriented programming term: a class that contains methods for other classes.
*Mixin* --es un término genérico de programación orientado a objetos: una clase que contiene métodos para otras clases.
Some other languages allow multiple inheritance. JavaScriptdoes not support multiple inheritance, butmixinscan be implemented by copying methods into prototype.
Algunos lenguajes permiten la herencia múltiple. JavaScriptno admite la herencia múltiple, pero losmixinsse pueden implementar copiando métodos en el prototipo.
We can usemixinsas a way to augment a class by adding multiple behaviors, like event-handling as we have seen above.
Podemos usarmixinscomo una forma de expandir una clase agregando múltiples comportamientos, como el manejo de eventos que hemos visto anteriormente.
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 amixin,to minimize the probability of that happening.
Los mixins pueden convertirse en un punto de conflicto si sobrescriben accidentalmente los métodos de clase existentes. Por lo tanto, generalmente debes planificar correctamente la definición de métodos de unmixin,para minimizar la probabilidad de que suceda.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.