// Tutorial //

Using JavaScript Mixins

Published on February 12, 2019
Default avatar
By Vijay Prasanna
Developer and author at DigitalOcean.
Using JavaScript Mixins

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

When it comes to advanced class composition, JavaScript has quite a number of approaches - a true smorgasbord of options. A type of pattern that is rarely spotted in the wild is the mixin-based inheritance pattern. Mixins are usually skipped by new JavaScript programmers (I did it too). I don’t want to complain but mixins can sometimes be quite dense to write and comprehend. But they come with a bunch of features that are worth looking into.

The mixin pattern - as the name suggests - is a pattern of mixing together an object with other objects to add properties we need. Think of it like add-ons that can give your object additional properties, but these individual properties are not really subclasses themselves.

On the surface, mixins behave like object mixing layers, where we pass-in the target (the mixin) and the source. The target is appended to the source and a new object is returned.

A more accurate description is that a mixin works as factory where new a subclass object is returned. Through this whole process there is no definition of the subclass anywhere.

A more C++ analogy would be to compare them to abstract classes with virtual functions, allowing them to be inherited by other subclasses.

So, now that we know mixins allow us to create a modified definition that can be applied to existing superclasses to create new subclasses, let’s see how mixin would look like:

//The swim property here is the mixin
let swim = {
  location() {
    console.log(`Heading ${this.direction} at ${this.speed}`);
  }
};

let Alligator = function(speed, direction) {
  this.speed = speed,
  this.direction = direction
};

//This is our source object
let alligator = new Alligator('20 mph','North');

alligator = Object.assign(alligator, swim);
console.log(alligator.location());

In the above snippet, we want to create an alligator that can swim. So we create a new alligator and then give it the swim feature. The swim object is the mixin or an extension that we want the alligator object to have using the Object.assign method.

The Object.assign method allows us to add more than one mixin at a time. A multiple mixin case would look like this:

alligator = Object.assign(alligator, swim, crawl);

Now let’s look how mixins can be used with ES6 classes:

let swim = {
 setSwimProperties(speed, direction) {
   this.speed = speed;
   this.direction = direction;
 },

 getSwimProperties(){
   console.log(`swimming ${this.speed} towards ${this.direction}`);
 }
}

class Reptile {
 constructor(name) {
   this.name = name;
 }
}

Object.assign(Reptile.prototype, swim);
let alligator = new Reptile("alligator");
alligator.setSwimProperties("5 m/s", "upstream");
alligator.getSwimProperties();

The advantage of adding functionality via the mixin approach is flexibility. The mixin being a very primitive function, as in it does exactly one thing, allows us to use these structures repeatedly and in a variety of scenarios. It can used with a native function call, used in a class definition, etc.

Another good thing is that it tends to keep the class hierarchy horizontal - by allowing superclasses to use the mixins to create new objects of desired subclass properties rather than making the inheritance chain longer for creating new sublasses for these cases.

Some things to keep in mind when using mixins though:

  • The Object.assign (both in object and class implementation) does only a shallow copy of the mixin properties.
  • There can be potential name clashes while using properties from different mixins (the diamond problem in multiple inheritance)
  • It can be quite difficult to figure out from which mixin the property came from, since the properties are copied onto the source object. The instanceof operator cannot help us here.

Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in our Questions & Answers section, find tutorials and tools that will help you grow as a developer and scale your project or business, and subscribe to topics of interest.

Sign up
About the authors
Default avatar
Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?
Leave a comment