2

我正在为产品构建一个系列的概念,其中成员属于不同类型(accountHolderpayingCustomerstudent等)。最初我将它们FamilyMember构建为.studentpayingCustomeraccountHolder

鉴于对象组合在 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's 方法isOfAge能够访问 property isAdult,因为它在对象中。但是,从概念上讲,我理解它为什么不起作用:isOfAge是 的方法state,而不是结果adult实例。

如果我使用类甚至是传统的原型/构造器机制,我知道如何使其工作(例如附加到prototype)。对于对象组合,我不知道如何到达那里,可能是由于缺乏 FP 经验。

谢谢您的帮助!

4

2 回答 2

1

您可以使用this代替stateinside 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'

于 2019-01-14T18:08:32.547 回答
1

对象组合

  • 由其他对象和语言原语组成的所有对象都是复合对象。

  • 创建复合对象的行为称为组合。
    ...

  • 连接通过使用新属性扩展现有对象来组合对象,例如Object.assign(destination, a, b), {...a, ...b}.
    ...
                          <br>对象组合的隐藏宝藏


所以从你的模式和工厂函数的使用来看,它看起来像连接吗?下面的演示是一个串联组合。请注意括在括号中的括号payment

const payment = (status) => ({...})

this 允许payment作为对象而不是函数返回。如果您有更灵活的数据,您将需要更少的方法。name: string并且age: number是我使用的属性,考虑到它是实用的还是在你的情况下name: stringadult: 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());

于 2019-01-15T00:04:37.070 回答