Search code examples
javascriptclassinheritanceecmascript-6subclass

Class inheritance - add argument without rewriting parent constructor arguments


I would like to extend the following class:

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

...by adding sport and its getter:

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

While the above works, I would like to avoid repeating the arguments of the base-parent constructor. The following approach won't work:

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'

So, how can I add fields to the subClass without rewriting the ones of the base Class?


Solution

  • What you want can be achieved (using destructured parameters (...args) syntax to denote an arbitrary number of arguments), however, it is not advised (at least the way I did it), and it comes at certain costs, some of which are readability, ease of debugging, lesser error-prone code, and more (since this makes the code a little more obscure, making the order of the arguments not that clear and making it possible to pass the wrong number of 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(...args) {
            let sport = args.pop();
            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);

    It can similarly be achieved using the arguments object:

    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.pop();
            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);