Методы объекта, созданного с помощью композиции, не могут получить доступ ко всем свойствам - PullRequest
0 голосов
/ 14 января 2019

Я создаю концепцию семьи для продукта, члены которого бывают разных типов (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.

Спасибо за помощь!

Ответы [ 2 ]

0 голосов
/ 15 января 2019

Состав объекта

  • Все объекты, созданные из других объектов и языковых примитивов, являются составными объектами.

  • Акт создания составного объекта известен как композиция.
    ...

  • Конкатенация создает объекты путем расширения существующего объекта новыми свойствами, например, Object.assign(destination, a, b), {...a, ...b}.
    ...
    Скрытые сокровища композиции объекта

Итак, из вашего шаблона и использования фабричной функции это выглядит как конкатенация? Демонстрация ниже представляет собой составную композицию. Обратите внимание на круглые скобки, заключенные в скобки 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());
0 голосов
/ 14 января 2019

Вы можете использовать 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'
...