Javascript 中的组合模式与 类 但没有 Mixins?
Composition Pattern in Javascript with Classes but without Mixins?
以下是在 Javascript 中实现组合模式的有效策略吗?我想使用 类 而不是构造函数或普通对象,而且我知道 Mixins 不是最佳实践。一个问题是,在这种方法中,添加到 Person
对象的方法没有附加到原型,因此每个方法都需要分配内存。谢谢!
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());
}
...the methods added to Person
objects are not attached to the prototype and therefore each require memory allocation
是的,但这是一个微不足道的数量,每个对象每个方法一个 属性 的成本(保存方法的函数引用)。属性不是无,但它们并不大。为避免疑义:function 对象被所有实例重用,而不是被复制。
fly
和 swim
没有理由成为函数(至少,none 从问题中可以明显看出),直接使用对象即可:
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);
}
请注意,这仍在使用 mixin(您的原始版本和上面的版本)。
除非您打算将 fly
/flyMethods
和 swim
/swimMethods
与 Person
以外的其他 类 重用,尽管,使用 extends
看起来更简单,并且会给你原型方法重用:
class FlyingPerson extends Person {
fly() {
// ...
}
}
如果你正在重用fly
/flyMethods
等,有多个类,另一种选择是建厂从各种方法集创建原型然后重用它的函数:
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();
以下是在 Javascript 中实现组合模式的有效策略吗?我想使用 类 而不是构造函数或普通对象,而且我知道 Mixins 不是最佳实践。一个问题是,在这种方法中,添加到 Person
对象的方法没有附加到原型,因此每个方法都需要分配内存。谢谢!
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());
}
...the methods added to
Person
objects are not attached to the prototype and therefore each require memory allocation
是的,但这是一个微不足道的数量,每个对象每个方法一个 属性 的成本(保存方法的函数引用)。属性不是无,但它们并不大。为避免疑义:function 对象被所有实例重用,而不是被复制。
fly
和 swim
没有理由成为函数(至少,none 从问题中可以明显看出),直接使用对象即可:
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);
}
请注意,这仍在使用 mixin(您的原始版本和上面的版本)。
除非您打算将 fly
/flyMethods
和 swim
/swimMethods
与 Person
以外的其他 类 重用,尽管,使用 extends
看起来更简单,并且会给你原型方法重用:
class FlyingPerson extends Person {
fly() {
// ...
}
}
如果你正在重用fly
/flyMethods
等,有多个类,另一种选择是建厂从各种方法集创建原型然后重用它的函数:
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();