问题
Composition is a useful alternative to inheritance when one wants to cascade method calls from child to parent, see child extended class method calls its super version but that still only sees child data
However, for the child to present an interface that is compatible with parent type, one must implement a potentially large number of stub methods that all have the same form, namely they just relay the call to the former parent (which is now a component).
My question here, is it possible to write a catch-all method? A catch-all method would be called when none of the other methods are called. The catch-all would then just relay calls to the parent component. Thus the stub would only have to be written once. Variations could be used to sort multiple inheritance, etc.
Something like this:
class A {
constructor(){
this.x = "super x!";
}
f(){
console.log("I am a super f()!");
}
logx(){
this.f();
console.log(this.x);
}
}
class B {
constructor(){
this.a = new A();
this.x = "derived x.";
}
f(){
console.log("I am a derived f()");
}
logx(){
this.a.logx();
}
}
let b = new B;
b.logx();
I am a super f()!
super x!
Hypothetically would instead be something like this:
class A {
constructor(){
this.x = "super x!";
}
f(){
console.log("I am a super f()!");
}
logx(){
this.f();
console.log(this.x);
}
}
class B {
constructor(){
this.a = new A();
this.x = "derived x.";
}
f(){
console.log("I am a derived f()");
}
catch_all(method_name, ...args){
this.a.method_name(...args);
}
}
let b = new B;
b.logx();
I am a super f()!
super x!
回答1:
Using Fred Truter's function to pull methods from a class Iterate through methods and properties of an ES6 class:
Object.methods = function (klass) {
const properties = Object.getOwnPropertyNames(klass.prototype)
properties.push(...Object.getOwnPropertySymbols(klass.prototype))
return properties.filter(name => {
const descriptor = Object.getOwnPropertyDescriptor(klass.prototype, name)
if (!descriptor) return false
return 'function' == typeof descriptor.value && name != 'constructor'
})
}
class A {
constructor() {
this.x = "super x!";
}
f() {
console.log("I am a super f()!");
}
logx() {
console.log(this.x + "log");
}
}
class B {
constructor() {
this.a = new A();
this.x = "derived x. ";
Object.methods(A).forEach(method => this[method] = this.a[method]);
}
logx() {
console.log(this.x + "log")
}
}
let b = new B;
b.f(); //"I am a super f()!"
b.logx(); //"derived x. log"
回答2:
This builds on isepa's suggestion to use Fred Truter's function for listing methods. That is a nice concept, but it doesn't quite get us there. It needs a test so as not to clobber existing methods. Also just copying the methods is problematic because the parent this.variables won't be there or will alias in the child - note this is composition so they weren't intended to be inherited. Instead of copying, this turns it into a call.
//Fred Truter's function:
Object.methods = function (klass) {
const properties = Object.getOwnPropertyNames(klass.prototype)
properties.push(...Object.getOwnPropertySymbols(klass.prototype))
return properties.filter(name => {
const descriptor = Object.getOwnPropertyDescriptor(klass.prototype, name)
if (!descriptor) return false
return 'function' == typeof descriptor.value && name != 'constructor'
})
}
Object.compose = function (obj0, obj1, ...constructor_args) {
obj0[obj1.name] = new obj1(...constructor_args);
Object.methods(obj1).forEach(
method => {
if(!obj0[method]) obj0[method] = (...args) => obj0[obj1.name][method](...args);
}
);
}
// shows using the composition operator:
class A {
constructor(){
this.x = "super x!";
}
f(){
console.log("I am a super f()!");
console.log(this.x);
}
logx(){
console.log(this.x);
this.f();
}
}
class B {
constructor(){
Object.compose(this, A);
this.x = "derived x.";
}
// f(){ console.log("I am a derived f()"); }
logx(){
console.log(this.x);
this.f();
}
}
let b = new B;
b.logx();
b.f();
And the outputs, as expected:
derived x.
I am a super f()!
super x!
I am a super f()!
super x!
Then upon removing the comment from the child version of f, we get, as expected:
derived x.
I am a derived f()
来源:https://stackoverflow.com/questions/55691740/es6-et-al-is-it-possible-to-define-a-catch-all-method