通过组合创建的对象上的方法无法访问所有属性

Methods on an object created via composition can't access all properties

我正在为一个产品构建一个系列的概念,其中的成员有不同的类型(accountHolderpayingCustomerstudent,等等)。最初我将它们构建为 FamilyMember 的子 类,但我最终得到了一些重复的代码并最终遇到了一个重大问题:我们平台的 student 也可以是唯一的 payingCustomeraccountHolder.

鉴于对象组合在 JS 中被广泛吹捧为一个好主意,我决定走那条路。但是,如果 属性 属于另一个对象类型(例如 student),则特定对象类型(例如 accountHolder)的方法无法访问实例化对象的属性。

为了更进一步 objective 我决定使用以下代码复制该行为:

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,因为它在对象中。但是,从概念上讲,我理解为什么它不起作用:isOfAgestate 的方法,而不是结果 adult 实例。

如果我使用 类 甚至是传统的 prototype/constructor 机制,我知道如何让它工作(例如附加到 prototype)。对于对象组合,我不知道如何实现,可能是因为缺乏 FP 经验。

感谢您的帮助!

您可以在 isOfAge 中使用 this 而不是 state。这样,当 isOfAge 方法被调用时,this 将被推导,它将被绑定到它被调用的任何对象。不过,您必须使用常规函数而不是箭头函数才能正常工作(箭头函数没有 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'

对象组合

  • All objects made from other objects and language primitives are composite objects.

  • The act of creating a composite object is known as composition.
    ...

  • Concatenation composes objects by extending an existing object with new properties, e.g., Object.assign(destination, a, b), {...a, ...b}.
    ...
                          
    The Hidden Treasures of Object Composition


所以从您的模式和对 factory function 的使用来看,它看起来像串联?下面的演示是一个串联组合。请注意 payment:

括号中的括号
const payment = (status) => ({...})

这允许 payment 作为对象而不是函数返回。如果您的数据更灵活一些,您将需要更少的方法。 name: stringage: 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());