编辑:我已添加更新的屏幕截图(最后),以便进一步说明。
我正在尝试使用高阶函数来编写子类/ 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
有人可以解释我做错了吗?
答案 0 :(得分:2)
在new enhancedClass('Edgar')
,会发生这种情况:
lastNameClass
的构造函数调用super
middleNameClass
的构造函数调用super
Person
的构造函数调用super
firstNameClass
执行this.firstName = 'Edgar'
Person
,调用getNames
middleNameClass
,this.middleName = 'Allan'
lastNameClass
,this.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 ()}`)
}
好的,现在我们可以看到一些模块如何由其他模块组成。在我们查看inherit
和method
之前,让我们看看我们如何使用我们的模块
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
,使您能够定义具有相同名称的新方法,但仍然允许调用者访问这两种方法privateMethod
或classMethod
帮助field
以在值更改时发出事件field
以便无法设置值,其中mutableField
可用于可以更改的字段写下你想要的方式然后让你的愿望成真。您拥有任何限制。