What is the difference between composition and inheritance?
Two ways to reuse and combine behaviour.
Inheritance — a class extends a parent, gaining its features (an "is-a" relationship). Deep hierarchies can become rigid.
Composition — build objects by combining small, focused pieces of behaviour (a "has-a" relationship). More flexible.
Common advice: "favour composition over inheritance" — it avoids tight coupling and fragile class trees.
// Inheritance
class Animal {
speak() { return 'Some sound'; }
}
class Dog extends Animal {
speak() { return 'Woof!'; }
}
// Composition (preferred)
const canSwim = (state) => ({
swim: () => `${state.name} is swimming`
});
const canFly = (state) => ({
fly: () => `${state.name} is flying`
});
const canWalk = (state) => ({
walk: () => `${state.name} is walking`
});
// Duck can walk, swim, AND fly — no class hierarchy needed
function createDuck(name) {
const state = { name };
return {
...canWalk(state),
...canSwim(state),
...canFly(state),
quack: () => `${name} says quack!`
};
}
const duck = createDuck('Donald');
console.log(duck.swim()); // 'Donald is swimming'
console.log(duck.fly()); // 'Donald is flying'
console.log(duck.quack()); // 'Donald says quack!'Inheritance: Dog extends Animal (single chain). Composition: canSwim, canFly, canWalk are mixins — combined freely with spread.
Duck composes all three behaviors without a class hierarchy. Adding a new behavior (canDive) is just another function — no refactoring the inheritance tree.
'Favor composition over inheritance' is the principle. Show the duck example: composing behaviors from multiple sources (impossible with single class inheritance).
Composition = loose coupling, easy testing, flexible combination. Inheritance = tight coupling, single chain.