¿Es la siguiente una estrategia válida para implementar el patrón de composición en Javascript? Quiero usar clases en lugar de funciones de constructor u objetos simples, y sé que los Mixins no son las mejores prácticas. Una preocupación es que en este enfoque, los métodos agregados a los objetos Person no están adjuntos al prototipo y, por lo tanto, cada uno requiere asignación de memoria. ¡Gracias!
class Person { name; constructor(name) { this.name = name; } } function fly() { return { fly() { console.log(`${this.name} can fly!`); }, }; } function swim() { return { swim() { console.log(`${this.name} can swim!`); }, }; } function makeFlyingPerson(name) { return Object.assign(new Person(name), fly()); } function makeSwimmingPerson(name) { return Object.assign(new Person(name), swim()); }...los métodos agregados a los objetos
Personno están adjuntos al prototipo y, por lo tanto, cada uno requiere asignación de memoria
Cierto, pero es una cantidad trivial, el costo de una propiedad por método por objeto (para mantener la referencia de función para el método). Las propiedades no son nada , pero no son grandes. Para evitar dudas: el objeto de función es reutilizado por todas las instancias, no copiado.
Sin embargo, no hay razón para que fly y swim sean funciones (al menos, ninguna que se desprenda de la pregunta), solo use los objetos directamente:
class Person { name; constructor(name) { this.name = name; } } const flyMethods = { fly() { console.log(`${this.name} can fly!`); }, }; const swimMethods = { swim() { console.log(`${this.name} can swim!`); }, }; function makeFlyingPerson(name) { return Object.assign(new Person(name), flyMethods); } function makeSwimmingPerson(name) { return Object.assign(new Person(name), swimMethods); }Sin embargo, tenga en cuenta que esto todavía está usando mixins (tanto su original como el anterior).
Sin embargo, a menos que vaya a reutilizar fly / flyMethods y swim / swimMethods con otras clases que no sean Person , el uso de extends parecería más simple y le daría una reutilización prototípica del método:
class FlyingPerson extends Person { fly() { // ... } } Si está reutilizando fly / flyMethods , etc., con varias clases, otra opción es tener funciones de creación de fábrica que creen un prototipo a partir de varios conjuntos de métodos y luego lo reutilicen:
class Person { name; constructor(name) { this.name = name; } } const flyMethods = { fly() { console.log(`${this.name} can fly!`); }, }; const swimMethods = { swim() { console.log(`${this.name} can swim!`); }, }; function extendWith(cls, name, ...mixins) { // We use the wrapper object so that the class constructor's name is assigned from `name` const obj = { [name]: class extends cls { } }; Object.assign(obj[name].prototype, ...mixins); return obj[name]; } const FlyingPerson = extendWith(Person, "FlyingPerson", flyMethods); const SwimmingPerson = extendWith(Person, "SwimmingPerson", swimMethods); const FlyingSwimmingPerson = extendWith(Person, "FlyingSwimmingPerson", flyMethods, swimMethods); const joe = new FlyingSwimmingPerson("Joe"); joe.fly(); joe.swim(); class Animal { name; type; constructor(name, type) { this.name = name; this.type = type; } } const FlyingSwimmingAnimal = extendWith(Animal, "FlyingSwimmingAnimal", flyMethods, swimMethods); console.log(FlyingSwimmingAnimal.name); // FlyingSwimmingAnimal const splippery = new FlyingSwimmingAnimal("Slippery"); splippery.fly(); splippery.swim();