我正在学习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()
我仍在学习中,所以我只需要一些指示。
答案 0 :(得分:1)
它或多或少地完成了您的预期?然后,确保这是一种正确的方法,无论“正确”在这里是什么意思。
在我看来,它就像我将其弹出到控制台中时一样。我真的不能在您的代码上多说什么,因为除了将Ducks分解成原子块之外,我不确定它要建模的具体领域。
但是,如果您要这样做,我个人更喜欢使用params对象,而不是像AnimalsWithWings
那样更改构造函数签名。这样,额外参数化的顺序并不取决于应用混合的顺序,我认为这是一个惊喜。惊喜很糟糕。
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 });
}
}
就个人观点而言,我将其命名为WithDiving
和WithWings
,只是为了保持某种一致的命名方案,并更好地暗示它们是修饰符,而不是“真实的”基类
您的代码确实使每个Duck都拥有一个原型链,每个原型链有4个较长的原型,但是,无论如何。如果某种原因导致性能出现问题,则可以创建一个实用程序函数来优化混入过程或其他操作。压平原型。
您的代码还允许您在方法中调用super.method()
,尽管您是否应该在mixin中使用它一直是有争议的。我会说你不应该,除非你想让你的mixins隐式地相互依赖,这是一个惊喜。
还有很多其他的混合方法。
Object.assign()
/ get
访问器之类的东西,请务必迭代属性描述符,而不仅仅是在进行平坦化时仅使用set
)。Object.create()
创建实例。 (关于迭代属性描述符的同样操作。)Object.create()
的一堆迭代调用来创建Duck原型,而不是迭代地扩展基类。