Mixins, Composition vs Inheritance Patterns
Is-A chhodo, Has-A apnao. Mixins se jodo, Composition se todo.
Inheritance means "Is-A" — Dog is an Animal, Car is a Vehicle. The child class extends the parent and inherits all its properties and methods.
JavaScript supports single inheritance only — a class can only extend one parent. No multiple inheritance like C++ or Python.
class Animal {
breathe() { return "breathing"; }
}
class Dog extends Animal {
bark() { return "woof"; }
}
const rex = new Dog();
console.log(rex.breathe()); // Inherited
console.log(rex.bark()); // Own
// The problem: What if Dog needs to swim?
// Cannot extend both Animal AND Swimmer!
// class Dog extends Animal, Swimmer {} // SyntaxError!
Problems with inheritance:
1. Fragile base class — a change in the parent can break all children silently.
2. Deep hierarchies become rigid — Animal > Mammal > Canine > Dog > Puppy. Six levels just to add a tail wag.
3. "Is-A" doesn't fit every scenario — Dog can walk AND swim. Which parent does it extend?
serialize() but you inherit 40 methods you never called.When inheritance works well: Clear "is-a" relationships — Array is an Object, Error is a Throwable. Shallow hierarchies (1-2 levels) are fine.
A Mixin is a way to add methods to a class without using extends. It bridges the gap of multiple inheritance — a class can receive behavior from many mixins.
Object.assign Mixin: Copy methods directly onto the prototype.
// Mixin Objects
const swimMixin = {
swim() { return "swimming"; }
};
const fetchMixin = {
fetch() { return "fetching"; }
};
// Apply mixins to prototype
class Dog {}
Object.assign(Dog.prototype, swimMixin, fetchMixin);
const rex = new Dog();
console.log(rex.swim()); // "swimming"
console.log(rex.fetch()); // "fetching"
Class Factory Mixin: A function that takes a base class and returns a new class extending it.
// Class Factory Mixin (cleaner pattern)
const Swimmer = (Base) => class extends Base {
swim() { return "swimming"; }
};
const Fetcher = (Base) => class extends Base {
fetch() { return "fetching"; }
};
class Animal {
breathe() { return "breathing"; }
}
class Dog extends Fetcher(Swimmer(Animal)) {
bark() { return "woof"; }
}
const buddy = new Dog();
console.log(buddy.swim()); // From Swimmer mixin
console.log(buddy.fetch()); // From Fetcher mixin
console.log(buddy.breathe()); // From Animal base
Drawbacks of mixins: (1) Method name collisions — two mixins with the same method name, last one wins silently. (2) Harder to debug — where did a method come from? (3) Implicit dependencies — mixins may expect certain properties on the target.
Composition flips the paradigm: instead of "Dog IS a Swimmer", think "Dog HAS the ability to swim". Build objects from smaller, focused pieces rather than inheriting from large base classes.
Delegation: Dog holds a reference to a swimmer object and delegates the swim call. The dog doesn't inherit swimming — it has a swimming capability.
// Capabilities as standalone objects
const canSwim = {
swim() { return this.name + " swims"; }
};
const canBark = {
bark() { return this.name + " barks"; }
};
// Compose a Dog by combining capabilities
function createDog(name) {
const state = { name };
// Combine behavior and state
return {
...state,
...canSwim,
...canBark
};
}
const rex = createDog("Rex");
console.log(rex.swim()); // "Rex swims"
console.log(rex.bark()); // "Rex barks"
Adding new capabilities is trivial — no class hierarchy changes needed:
const canFly = {
fly() { return this.name + " flies"; }
};
function createBird(name) {
return { ...{ name }, ...canSwim, ...canFly };
}
const eagle = createBird("Eagle");
console.log(eagle.swim()); // "Eagle swims"
console.log(eagle.fly()); // "Eagle flies"
Why composition wins: Each piece is independent, testable in isolation, and reusable. You pick only what you need — no gorilla, no jungle, just the banana. 🍌
A Functional Mixin is a function that takes an object and adds properties/methods to it. The real power: it can use closures to add truly private state.
Unlike object mixins (which are just property copies), functional mixins can encapsulate private data that no outside code can access.
// Functional Mixin with private state
function withLogging(obj) {
let logCount = 0; // Private to the mixin!
Object.assign(obj, {
log(message) {
logCount++;
console.log("[" + logCount + "] " + message);
},
getLogCount() {
return logCount;
}
});
return obj;
}
const service = { name: "AuthService" };
withLogging(service);
service.log("User logged in");
service.log("Token refreshed");
console.log(service.getLogCount()); // 2
// service.logCount -> undefined (private!)
logCount variable lives in the closure scope of withLogging. The log and getLogCount methods can read/write it, but no external code can access service.logCount directly. This is true encapsulation without classes — pure JavaScript closure magic.When to use functional mixins: When you need private state mixed into existing objects, when you want to add logging/caching/validation to any object without modifying its class.
Not every problem needs the same tool. Here's your decision matrix:
// Decision Matrix
// IS-A? → Inheritance (Array extends Object)
// CAN-DO? → Mixin (canSerialize, canValidate)
// HAS-A? → Composition (Car has Engine)
// CHANGES? → Composition (swap behavior at runtime)
Use Inheritance when:
• Clear "is-a" relationship (Dog is an Animal)
• Single base class, shallow hierarchy (1-2 levels max)
• Child truly is a specialized version of the parent
Use Mixins when:
• Need to share behavior across unrelated classes
• Adding capabilities (Serializable, Loggable, Validatable)
• Cannot change the class hierarchy but need to extend it
Use Composition when:
• Behavior changes at runtime (swap strategies)
• Need many small, independent pieces
• Want to avoid deep, rigid hierarchies
Lo kar liya — Key Points:
- ✅ Inheritance is "is-a" (Dog is Animal); JS supports single inheritance only
- ✅ Mixins add behavior to classes without inheritance via Object.assign or class factories
- ✅ Composition is "has-a" (Dog has the ability to swim); build objects from small pieces
- ✅ Functional mixins can encapsulate private state using closures
- ✅ Favor composition over inheritance — more flexible, testable, avoids deep hierarchies
- ✅ Modern frameworks (React hooks, Vue composables) use composition, not inheritance
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login