3

I am attempting to pass a test suite utilizing inheritance through JavaScript. Below is a snippet of the code I have so far:

var Infant = function() {
    this.age  = 0;
    this.color = 'pink';
    this.food = 'milk';

};
Infant.prototype.eat = function(){
    return this.eat;
}


var Adolescent = function() {

    this.age = 5;
    this.height = 'short';
    this.job = 'keep on growing';

};

I would like to inherit the food property from the Infant class and the eat method but my attempts have fallen short. my initial thought was to assign this.Adolescent = Infant.food; but that didn't work. I know I need to set Infant as the Superclass but I'm spinning my wheels

DLF85
  • 189
  • 4
  • 12

1 Answers1

7

When using constructor functions for inheritance in JavaScript, you:

  1. Make the prototype property of the "derived" constructor an object whose prototype is the prototype property of the "base" constructor.

  2. Set the constructor property on the "derived" constructor's prototype property to point to the "derived" constructor.

  3. Call the "base" constructor from the "derived" constructor with the correct this.

Like this:

var Infant = function() {
    this.age  = 0;
    this.color = 'pink';
    this.food = 'milk';
};
Infant.prototype.eat = function(){
    return /*...something...*/; // Returning `this.eat` doesn't make any sense, that's the function we're in
};

var Adolescent = function() {

    // #3 Give super a chance to initialize the instance, you can pass args if appropriate
    Infant.call(this);

    this.age = 5;
    this.height = 'short';
    this.job = 'keep on growing';
};

// Set up Adolescent's prototype, which uses Infant's prototype property as its prototype
Adolescent.prototype = Object.create(Infant.prototype);     // #1
Object.defineProperty(Adolescent.prototype, "constructor",  // #2
    value: Adolescent,
    writable: true,
    configurable: true
});
// (In pre-ES5 environments that don't event have `Object.defineProperty`, you'd use
// an assignment instead: `Adolescent.prototype.constructor = Adolescent;`

Object.create was added in ES5, so it won't be present on obsolete JavaScript engines like the one in IE8. The single-argument version of it used above can be easily shimmed, though.

In ES2015 we have the option of doing it with the new class semantics:

class Infant {
    constructor() {
        this.age  = 0;
        this.color = 'pink';
        this.food = 'milk';
    }

    eat() {
        return /*...something...*/;
    }
}

class Adolescent extends Infant {            // extends does #1 and #2
    constructor() {
        super();                             // #3, you can pass args here if appropriate

        this.age = 5;
        this.height = 'short';
        this.job = 'keep on growing';
    }
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    Boooom! Great answer! – An0nC0d3r Jan 06 '16 at 09:20
  • Thank you so much! I am more used to the class semantics due to my initial coding knowledge being in Java. – DLF85 Jan 06 '16 at 09:31
  • @DLF85: Happy to help. Beware that prototypical inheritance is quite different to class-based inheritance such as Java's; the semantics above are mostly syntactic sugar, it's still prototypical inheritance regardless of the syntax. JS is so flexible it can mostly mimic class-based inheritance, but note the key difference that there really are separate objects involved (whereas in Java, it's one object that has features of both the base and derived classes). And of course, you're not limited to "classes" of objects; you can do inheritance with one-offs, which can be really handy. – T.J. Crowder Jan 06 '16 at 09:38
  • Also note that the new class semantics are brand new. If you want to use them in the wild, you have to use a transpiler (of which there are several; I use (but am not affiliated with) [Babel](http://babeljs.io). – T.J. Crowder Jan 06 '16 at 09:39
  • It seems I am still confused. I am now trying to add +1 to a value that is within the constructor class through a method outside the class but the console keeps telling me that my method is not a function. I feel that is may have to do with `this`. Everything inside the class runs fine it seems the method is `undefined` / `not a function` – DLF85 Jan 06 '16 at 10:51
  • @DLF85: Probably justifies a new question, so you can show the code. – T.J. Crowder Jan 06 '16 at 10:54
  • If using the first pattern, if both `Infant` and `Adolescent` take (the same) arguments, change `Infant.call(this)` to `Infant.apply(this,arguments)`. – JonBrave May 10 '17 at 10:59
  • @JonBrave: I would argue it's best to be explicit in most cases, but yes, that does work if you always want the subclass to pass on all its arguments to the super. The ES2015+ equivalent is `constructor(...args) { super(...args); }`. – T.J. Crowder May 10 '17 at 11:01
  • You are perhaps right. The reason is that I am abstracting your items #1, #2 & #3 into a single (generic) function. – JonBrave May 10 '17 at 11:08
  • 1) Why can't we access key-values defined in the parent class which is `Infant` without running `Infant.call(this);` over an object of `Adolescent`? – Soner from The Ottoman Empire Sep 02 '20 at 07:36
  • 2) What if we don't establish the constructor by using `Object.defineProperty`? I can also obtain same key-values whether it is used or not. Just object name changes. What is the drawback of/wrong with it? You can glance at the gif image to get me better, sir. ----> https://i.stack.imgur.com/7a6BF.gif – Soner from The Ottoman Empire Sep 02 '20 at 07:48
  • Sir, could you find an opportunity to glance at my two questions above? – Soner from The Ottoman Empire Sep 02 '20 at 14:50
  • @snr - Re #1, it's because no code has been run to create those properties on the instance. You need to call `Infant` to set up the `Infant` information on the object. Re #2, see the first paragraph of [this answer](https://stackoverflow.com/a/10836157/157247) and perhaps [this question's answers](https://stackoverflow.com/questions/4012998/what-it-the-significance-of-the-javascript-constructor-property), though note that many are outdated (they were right at the time). HTH. – T.J. Crowder Sep 02 '20 at 15:34