JavaScript 的组合和混合

Composition and Mixins with JavaScript

我正在学习 Javascript 中的作文。所以我想问一下这是否是正确的做事方式。

我做了一些看起来像这样的练习:

    class Animal {
    // constructor() {
    // }
    eat = () => {
        console.log("this creature is eating");
    }
}

const AnimalsWithWings = superclass => class extends superclass {
    constructor(Feathers, ...args) {
        super(...args);
        Object.assign(this, { Feathers });
    }
}

const CanDive = superclass => class extends superclass {
    // constructor( ...args) {
    //     super(...args);
    // }
    dive = () => {
        console.log("Can Dive");
    }
}

class Duck extends AnimalsWithWings(CanDive(Animal)) {
    constructor(eats, ...args) {
        super(...args);
        Object.assign(this, { eats });
    }
}

const duffy = new Duck("watermelon", true);
console.log(duffy);

duffy.dive();
duffy.eat()

我还在学习过程中,所以我只需要一些指导。

它是否或多或少达到了您的预期?然后,当然,这是 a 正确的方法,无论 "correct" 在这里意味着什么。

在我看来,当我将它弹出到控制台时,它就像它应该做的那样。关于你的代码,我真的不能说更多,因为我不确定它试图建模的具体领域是什么,除了可能将 Ducks 分解成原子块。

不过,如果您要这样做,我个人更喜欢使用参数对象,而不是像 AnimalsWithWings 那样只更改构造函数签名。这样一来,额外参数化的顺序就不会依赖于 mixins 的应用顺序,我认为这是一个惊喜。惊喜是不好的。

const AnimalsWithWings = superclass => class extends superclass {
    // Everyone receives the same `params` object.
    // They only take what they know about, and ignore the rest.
    constructor(params) {
        super(params);
        Object.assign(this, { Feathers: params.Feathers });
    }
}

更个人意见,我将它们命名为 WithDivingWithWings,只是为了保持命名方案的一致性,并更好地暗示这些是修饰符,而不是 "real" 基础 classes.

您的代码确实为每只 Duck 配备了 4 个原型长的原型链,但是,呃,随便吧。如果它以某种方式成为性能问题,那么您可以创建一个实用函数来优化混合过程或其他东西。可能会将原型压平。

您的代码还允许您在方法中调用 super.method(),尽管您是否应该在混入中使用它是值得商榷的。我会说你不应该,除非你希望你的 mixins 隐式地相互依赖,这是一个惊喜。

还有很多其他的混合方法。

  • 您可以创建一个效用函数,将所有原型展平为一个新原型,并 return 一个基础 class 从中扩展。 (如果您想正确处理 get/set 访问器等内容,请确保在进行扁平化时迭代 属性 描述符而不是仅使用 Object.assign() 。)
  • 您可以避开 类 并直接创建原型对象并使用 Object.create() 创建实例。 (迭代 属性 描述符也是如此。)
  • 您可以使用对 Object.create() 的一系列迭代调用来创建 Duck 原型,而不是迭代扩展基础 classes.
  • 您可以使用辅助控制器 类 控制额外的行为,而不是直接将行为组合到基础中。
  • 您可以仅在普通对象中处理数据,并将对象传递给函数,这些函数期望对象具有某些属性以便执行操作。 (有趣的是,称为 "duck typing")我承认这不是真正的混合,只是调用函数,但如果它实际上完成了同样的事情...
  • 可能还有其他一些我现在真的想不起来。都是将一系列行为附加到一些基本的东西上。