ES6 et al. is it possible to define a catch-all method?

不问归期 提交于 2019-12-13 03:49:44

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!