为什么高阶函数隐藏了我的ES6类属性?

时间:2018-04-01 00:49:24

标签: javascript class inheritance ecmascript-6 functional-programming

编辑:我已添加更新的屏幕截图(最后),以便进一步说明。

我正在尝试使用高阶函数来编写子类/ mixins,但注意到我只能访问我扩展的第一个类的属性,并且只能访问任何后续类的属性< em>在之后我打电话给了班级。这是我的意思的一个人为的例子:

这些函数将子类应用于父类:

export const middleNameClass = middlename => BaseClass => {
  return class extends BaseClass {
    constructor(args) {
      super(args);
      this.middlename = middlename;
    }
  };
};

export const lastNameClass = lastname => BaseClass => {
  return class extends BaseClass {
    constructor(args) {
      super(args);
      this.lastname = lastname;
    }
  };
};

以下是firstNameClass,它将由父类Person直接扩展:

class firstNameClass {
  constructor(args) {
    this.firstname = args;
  }
}

这是Person,扩展了firstNameClass

class Person extends firstNameClass {
  constructor(args) {
    super(args);
    this.getNames = this.getNames.bind(this);

    // I'm using to log class properties to the console
    this.getNames();
  }

  getNames() {
    console.log("this inside getNames(): ", this);
    console.log("firstnames inside getNames(): ", this.firstname);
    console.log("middlenames inside getNames(): ", this.middlename);
    console.log("lastnames inside getNames(): ", this.lastname);
  }
}

最后,这里是我应用高阶函数并创建我的类的地方:

const enhancedClass = compose(
  middleNameClass("Allan"),
  lastNameClass("Poe")
)(Person);

const namedPerson = new enhancedClass("Edgar");

但是,当我检查console.log时,我看到以下内容:

this.firstnames inside getNames(): Edgar
this.middlenames inside getNames(): undefined
this.lastnames inside getNames(): undefined

有人可以解释我做错了吗?

修改 以下是我的Person课程的内容: enter image description here

以下是创建类后输出到控制台的内容: the

2 个答案:

答案 0 :(得分:2)

new enhancedClass('Edgar'),会发生这种情况:

  • lastNameClass的构造函数调用super
  • middleNameClass的构造函数调用super
  • Person的构造函数调用super
  • firstNameClass执行this.firstName = 'Edgar'
  • 返回Person,调用getNames
  • 返回middleNameClassthis.middleName = 'Allan'
  • 返回lastNameClassthis.lastName = 'Poe'

之后调用getNames应该有效。如果你每次都使用extend就会发生同样的事情。

答案 1 :(得分:1)

这不是您问题的答案,但可能是您问题的解决方案

JavaScript没有多重继承,但幸运的是,函数式编程与JavaScript的类系统,对象原型或其他面向对象的概念无关。功能编程所有关于函数!

我们开始用一些函数编写可继承的模块

// module 1
const hasFirstName = (firstName = "") => o =>
{
  field (o, 'firstName', firstName)
}

// module 2
const hasMiddleName = (middleName = "") => o =>
{
  field (o, 'middleName', middleName)
}

// module 3
const hasLastName = (lastName = "") => o =>
{
  field (o, 'lastName', lastName)
}

我们还没有定义field,但不要担心。让我们看看下一个更复杂的模块

// module 4
const nameable = (first, middle, last) => o =>
{
  inherit (o, hasFirstName (first))
  inherit (o, hasMiddleName (middle))
  inherit (o, hasLastName (last))
  method (o, 'getFullName', (self) => `${self.firstName} ${self.middleName} ${self.lastName}`)
  method (o, 'sayHelloTo', (self, other) => `Hello ${other.getFullName ()}, my name is ${self.getFullName ()}`)
}

好的,现在我们可以看到一些模块如何由其他模块组成。在我们查看inheritmethod之前,让我们看看我们如何使用我们的模块

const Person = (first, middle, last) =>
  Obj (self => {
    inherit (self, nameable (first, middle, last))
  })

所以也许你对我在每个新代码粘贴中不断编写内容感到恼火,但这是一个非常强大的实践,称为wishful thinking

        

在实现组件之前,您需要编写一些实际使用的代码。通过这种方式,您可以发现您真正需要的参数功能,从而获得非常好的界面。您还将为组件提供一些良好的测试代码。

     

这个想法是基于这样一个事实:接口的目的是简化使用组件的代码,而不是简化实现它的代码。

在练习这个练习时,我们根据我们需要它做了一个虚构的对象系统 - not 基于JavaScript的对象系统的能力。

当然,我们希望使用我们的Person将是直截了当的

const p1 =
  Person ('Augusta', 'Ada', 'King-Noel', 166)

const p2 =
  Person ('Gerald', 'Jay', 'Sussman', 71)

console.log (p1.sayHelloTo (p2))
// Hello Gerald Jay Sussman, my name is Augusta Ada King-Noel

以下是依赖关系:我希望您在此处看到的是,不使用class甚至this。因此,即使JavaScript没有本机对象系统,这也表明您可以创建自己的

const Obj = (f, instance = {}) =>
  (f (instance), instance)

const inherit = (o, f) =>
  Object.assign (o, f (o))

const field = (o, name, value) =>
  Object.assign (o, { [name]: value })

const method = (o, name, f) =>
  Object.assign (o, { [name]: (...xs) => f (o, ...xs) })

完整的程序演示

// DIY class system
const Obj = (f, instance = {}) =>
  (f (instance), instance)
  
const inherit = (o, f) =>
  Object.assign (o, f (o))

const field = (o, name, value) =>
  Object.assign (o, { [name]: value })

const method = (o, name, f) =>
  Object.assign (o, { [name]: (...xs) => f (o, ...xs) })

// module 1
const hasFirstName = (firstName = "") => o =>
{
  field (o, 'firstName', firstName)
}

// module 2
const hasMiddleName = (middleName = "") => o =>
{
  field (o, 'middleName', middleName)
}
  
// module 3
const hasLastName = (lastName = "") => o =>
{
  field (o, 'lastName', lastName)
}

// module 4
const nameable = (first, middle, last) => o =>
{
  inherit (o, hasFirstName (first))
  inherit (o, hasMiddleName (middle))
  inherit (o, hasLastName (last))
  method (o, 'getFullName', (self) => `${self.firstName} ${self.middleName} ${self.lastName}`)
  method (o, 'sayHelloTo', (self, other) => `Hello ${other.getFullName ()}, my name is ${self.getFullName ()}`)
}

// Person class
const Person = (first, middle, last) =>
  Obj (self => {
    inherit (self, nameable (first, middle, last))
  })

// demo
const p1 =
  Person ('Augusta', 'Ada', 'King-Noel')

const p2 =
  Person ('Gerald', 'Jay', 'Sussman')

console.log (p1.sayHelloTo (p2))
// Hello Gerald Jay Sussman, my name is Augusta Ada King-Noel

我们的Person类显然可以定义自己的字段和方法

const dateDiff = (d1, d2) =>
  Math.abs (d1 - d2) / 1000 / 60 / 60 / 24 / 365 >> 0

const Person = (first, middle, last, birthdate = new Date) =>
  Obj (self => {
    inherit (self, nameable (first, middle, last))
    field (self, 'birthdate', birthdate)
    method (self, 'calculateAge', (self) => dateDiff (new Date, self.birthdate))
    method (self, 'sayAge', (self) => `I am ${self.calculateAge()} years old`)
  })

const p2 =
  Person ('Gerald', 'Jay', 'Sussman', new Date ('February 8, 1947'))

console.log (p2.sayAge ())
// I am 71 years old

发挥创意并发明您想要的任何其他功能

  • 也许您想制作一个overrideMethod,使您能够定义具有相同名称的新方法,但仍然允许调用者访问这两种方法
  • 也许您想要privateMethodclassMethod帮助
  • 可能会增强field以在值更改时发出事件
  • 可能会更改field以便无法设置值,其中mutableField可用于可以更改的字段

写下你想要的方式然后让你的愿望成真。您拥有任何限制。