Composition vs Inheritance in JavaScript

I was showing some of our juniors how to develop basic things in JavaScript and I realized there is a century-old (he-he) question – What to use: Composition or Inheritance when creating a hierarchy of objects?

In highly structured languages like C#, the answer of the question is kinda obvious. Yes, it’s use Inheritance of classes. But this question comes more and more with TypeScript, React, and other languages based on JavaScript. There JS’s flexibility still exists but the creators want you to use the power of the classes. 

So, it depends. I personally prefer Composition in almost all situation because of many reasons. Two of the main ones are:

  • for complex object hierarchy it creates readable and simpler code
  • gives better flexibility of what functions and elements to inherit

You can google more reasons yourself and they will be all personal opinions. I would say, though, that more developers around me and on the Internet prefer the Composition over Inheritance.

And, to show you the difference, here is an example with two athletes.


class Person {
    walk() {
        console.log('I am walking...');
    }
    drive() {
        console.log('I am driving...');
    }
}

class Athlete extends Person { // but, athletes my or may not drive
    jump() {
        console.log('I am jumping...');
    }
}

let john = new Athlete();
let marrie = new Athlete();

marrie.jump();
marrie.drive();
john.jump();
john.drive(); // How to make Marrie a driver and John not?

Now, what is Composition?
You compose an object only of its needed parts. You break down all functionality into common pieces and pick the ones you need for each of your objects. At the end, you will have more combinations and less convoluted code.

As I said, with Composition you can decide what functions to add to each object by using Object.assign().


const walker = function () {
    return {
        walk: () => { console.log('I am walking...'); }
    }
}

const jumper = function () {
    return {
        jump: () => { console.log('I am jumping...'); }
    }
}

const driver = function () {
    return {
        drive: () => { console.log('I am driving...'); }
    }
}

const athleteDriver = function() {
    return Object.assign(
        {},
        walker(),
        jumper(),
        driver()
    );
};

const athlete = function() {
    return Object.assign(
        {},
        walker(),
        jumper(),
    );
};

var marrie = athleteDriver();
var john = athlete();

marrie.jump();
marrie.drive();
john.jump();
john.drive(); // undefined - John can't drive

Obviously, this example is oversimplified. Visibility of the functions is affected when using ‘this’. That’s a good candidate for another post.

I like what a fun guy said in a nice way on YouTube in 8 minutes. He gave me a good idea for decision making:

  • Use Inheritance when the relationship is “X is of Y type”.
  • Use Composition when the relationship is “X has a Y capability.”

For example, Woman is a Human and Woman can give birth. Man is a Human (unless you ask my wife :) and Man cannot give birth. Try it on Codepen!

P.S. I thought this will be a quick, 5 minute write-up and it took almost 45 minutes. Well, software devs are really bad at estimating work, aren’t we?