我正在建立产品家族的概念,成员具有不同的类型(accountHolder
,payingCustomer
,student
等)。最初,我将它们构建为FamilyMember
的子类,但最终我得到了一些重复的代码,最终遇到了一个重大问题:我们平台的student
也可以是唯一的payingCustomer
和accountHolder
。
鉴于在JS中如何广泛宣传对象组合是一个好主意,我决定走这条路。但是,如果某个特定对象类型(例如accountHolder
)的方法属于另一种对象类型(例如student
),则无法访问实例化对象的属性。
为了更加客观,我决定使用以下代码来复制行为:
const person = (props) => {
let state = {
name: props.name,
}
state.isOfAge = () => {
// state.isAdult is always undefined because
// isAdult doesn't exist in this object
return state.isAdult === true
}
return state
}
const adult = (props) => {
return {
isAdult: true,
}
}
const factory = (props) => {
return Object.assign({}, person(props), adult(props))
}
const john = factory({
name: 'John',
})
console.clear()
console.log(john) // { isAdult: true, name: "John", isOfAge... }
console.log(john.isOfAge()) // false
我期望john
的方法isOfAge
能够访问属性isAdult
,因为它位于对象中。但是,从概念上讲,我理解为什么它不起作用:isOfAge
是state
的一种方法,而不是结果的adult
实例。
如果我使用的是类或什至是传统的原型/构造函数机制,我就会知道如何使之工作(例如,附加到prototype
上)。对于对象合成,我不知道如何到达那里,可能是由于缺乏FP的经验。
感谢您的帮助!
答案 0 :(得分:1)
您可以在this
中使用state
代替isOfAge
。这样,将在调用方法this
时推论isOfAge
,它将绑定到调用它的任何对象。但是,您必须使用常规函数而不是箭头来起作用(箭头函数没有this
):
const person = (props) => {
let state = {
name: props.name,
}
state.isOfAge = function() { // use a regular function
return this.isAdult === true // use this here instead of state
}
return state
}
const adult = (props) => {
return {
isAdult: true,
}
}
const factory = (props) => {
return Object.assign({}, person(props), adult(props))
}
const john = factory({
name: 'John',
})
console.log(john);
console.log(john.isOfAge()); // returns 'true' because 'this' inside 'isOfAge' will be 'john'
答案 1 :(得分:1)
由其他对象和语言原语构成的所有对象都是复合对象。
创建复合对象的动作称为“组合”。
...- 串联通过扩展具有新属性(例如
Object.assign(destination, a, b), {...a, ...b}
)的现有对象来构成对象。
...
The Hidden Treasures of Object Composition
从您的模式和使用factory function来看,它看起来像是串联的吗?下面的演示是串联组成。请注意,括号用payment
括起来:
const payment = (status) => ({...})
这允许payment
作为对象而不是函数返回。如果您拥有的数据更加灵活,则将需要更少的方法。我认为name: string
和age: number
是实用的属性,或者在您的情况下使用name: string
和adult: boolean
。
const payment = (status) => ({
adult: () => status.age > 17 ? true : false,
account: () => status.adult() ? 'holder' : 'student'
});
const member = (name, age) => {
let status = {
name,
age
};
return Object.assign(status, payment(status));
};
const soze = member('Kaiser Soze', 57);
console.log(soze);
console.log(soze.adult());
console.log(soze.account());
const jr = member('Kaiser Soze Jr.', 13);
console.log(jr);
console.log(jr.adult());
console.log(jr.account());