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 });
}
}
更个人意见,我将它们命名为 WithDiving
和 WithWings
,只是为了保持命名方案的一致性,并更好地暗示这些是修饰符,而不是 "real" 基础 classes.
您的代码确实为每只 Duck 配备了 4 个原型长的原型链,但是,呃,随便吧。如果它以某种方式成为性能问题,那么您可以创建一个实用函数来优化混合过程或其他东西。可能会将原型压平。
您的代码还允许您在方法中调用 super.method()
,尽管您是否应该在混入中使用它是值得商榷的。我会说你不应该,除非你希望你的 mixins 隐式地相互依赖,这是一个惊喜。
还有很多其他的混合方法。
- 您可以创建一个效用函数,将所有原型展平为一个新原型,并 return 一个基础 class 从中扩展。 (如果您想正确处理
get
/set
访问器等内容,请确保在进行扁平化时迭代 属性 描述符而不是仅使用 Object.assign()
。)
- 您可以避开 类 并直接创建原型对象并使用
Object.create()
创建实例。 (迭代 属性 描述符也是如此。)
- 您可以使用对
Object.create()
的一系列迭代调用来创建 Duck 原型,而不是迭代扩展基础 classes.
- 您可以使用辅助控制器 类 控制额外的行为,而不是直接将行为组合到基础中。
- 您可以仅在普通对象中处理数据,并将对象传递给函数,这些函数期望对象具有某些属性以便执行操作。 (有趣的是,称为 "duck typing")我承认这不是真正的混合,只是调用函数,但如果它实际上完成了同样的事情...
- 可能还有其他一些我现在真的想不起来。都是将一系列行为附加到一些基本的东西上。
我正在学习 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 });
}
}
更个人意见,我将它们命名为 WithDiving
和 WithWings
,只是为了保持命名方案的一致性,并更好地暗示这些是修饰符,而不是 "real" 基础 classes.
您的代码确实为每只 Duck 配备了 4 个原型长的原型链,但是,呃,随便吧。如果它以某种方式成为性能问题,那么您可以创建一个实用函数来优化混合过程或其他东西。可能会将原型压平。
您的代码还允许您在方法中调用 super.method()
,尽管您是否应该在混入中使用它是值得商榷的。我会说你不应该,除非你希望你的 mixins 隐式地相互依赖,这是一个惊喜。
还有很多其他的混合方法。
- 您可以创建一个效用函数,将所有原型展平为一个新原型,并 return 一个基础 class 从中扩展。 (如果您想正确处理
get
/set
访问器等内容,请确保在进行扁平化时迭代 属性 描述符而不是仅使用Object.assign()
。) - 您可以避开 类 并直接创建原型对象并使用
Object.create()
创建实例。 (迭代 属性 描述符也是如此。) - 您可以使用对
Object.create()
的一系列迭代调用来创建 Duck 原型,而不是迭代扩展基础 classes. - 您可以使用辅助控制器 类 控制额外的行为,而不是直接将行为组合到基础中。
- 您可以仅在普通对象中处理数据,并将对象传递给函数,这些函数期望对象具有某些属性以便执行操作。 (有趣的是,称为 "duck typing")我承认这不是真正的混合,只是调用函数,但如果它实际上完成了同样的事情...
- 可能还有其他一些我现在真的想不起来。都是将一系列行为附加到一些基本的东西上。