【问题标题】:Class inheritance - add argument without rewriting parent constructor arguments类继承 - 添加参数而不重写父构造函数参数
【发布时间】:2021-05-30 22:59:53
【问题描述】:

我想扩展以下类:

class Person {
    constructor(name, age) {
        this._name = name;
        this._age = age;
    }
  
    get name() {
        return this._name;
    }
  
    get age() {
        return this._age;
    }
}

...通过添加 sport 及其 getter:

class Athlete extends Person {
    constructor(name, age, sport) {
        super();
        this._name = name;
        this._age = age;
        this._sport = sport;
    }
  
    get sport() {
        return this._sport;
    }
}

虽然上述方法有效,但我想避免重复基父构造函数的参数。以下方法不起作用:

class Athlete extends Person {
    constructor(sport) {
        super();
        this._sport = sport;
    }
  
    get sport() {
        return this._sport;
    }
}

let athlete = new Athlete('Peter', 29, 'cricket');
console.log(athlete.name, athlete.age, athlete.sport); // name and age are not inherited, is returned 'undefined'

那么,如何在不重写基类的情况下向子类添加字段?

【问题讨论】:

    标签: javascript class inheritance ecmascript-6 subclass


    【解决方案1】:

    可以实现您想要的(使用destructured parameters (...args) 语法来表示任意数量的参数),但是,不建议这样做(至少我这样做的方式),并且它出现在某些情况下成本,其中一些是可读性、易于调试、不易出错的代码等等(因为这会使代码更加晦涩难懂,使得参数的顺序不那么清晰,并且可以传递错误数量的论据):

    class Person {
        constructor(name, age) {
            this._name = name;
            this._age = age;
        }
      
        get name() {
            return this._name;
        }
      
        get age() {
            return this._age;
        }
    }
    
    class Athlete extends Person {
        constructor(...args) {
            let sport = args.splice(-1)[0];
            super(...args);
            this._sport = sport;
        }
        
        get sport() {
            return this._sport;
        }
    }
    
    let athlete = new Athlete('Peter', 29, 'cricket');
    console.log(athlete.name, athlete.age, athlete.sport);

    同样可以使用arguments对象实现:

    class Person {
        constructor(name, age) {
            this._name = name;
            this._age = age;
        }
      
        get name() {
            return this._name;
        }
      
        get age() {
            return this._age;
        }
    }
    
    class Athlete extends Person {
        constructor() {
            let args = Array.from(arguments);
            let sport = args.splice(-1)[0];
            super(...args);
            this._sport = sport;
        }
        
        get sport() {
            return this._sport;
        }
    }
    
    let athlete = new Athlete('Peter', 29, 'cricket');
    console.log(athlete.name, athlete.age, athlete.sport);

    【讨论】:

      【解决方案2】:

      您需要传递参数,但您可以通过将它们传递给 super() 来避免分配所有参数:

      class Athlete extends Person {
          constructor(name, age, sport) {
              super(name, age); // pass arguments to super()
              this._sport = sport;
          }
        
          get sport() {
              return this._sport;
          }
      }
      
      let athlete = new Athlete('Peter', 29, 'cricket');
      console.log(athlete.name, athlete.age, athlete.sport);
      

      【讨论】:

      • 所以,我还是要重复nameage。我看不出这种重复有什么意义,因为它们已经存在于基类中。
      • 这里是必须的,因为你想打电话给new Athlete('Peter', 29, 'cricket'),但你也想constructor(sport)。函数的签名不一样。 JS 无法自行决定参数的去向。
      • 想象一下你想要new Athlete('cricket', 'Peter', 29),JS怎么知道如何调度变量?
      • 如果参数的顺序是问题所在,我想可能会有[parent_arguments], child_argument_1, child_argument_2 这样的模式,而不必重复所有父参数。
      • 是的,如果你愿意,你可以打包父母的参数,但你会失去代码的可读性。 constructor([parent_arguments], sport) 需要引用父类,constructor(name, age, sport) 可以直接读取。
      猜你喜欢
      • 2011-12-08
      • 2018-03-31
      • 1970-01-01
      • 2013-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多