Mixins in JavaScript

Ben Aston
5 min readMar 9, 2015

The history of object-orientation begins somewhere around 1958 with the release of ALGOL. Its designers realized that by permitting attributes on procedures, useful “abstract objects” could be created.

Nine years later, SIMULA built upon earlier efforts and introduced classes as factories for objects, together with other now-familiar concepts such as inheritance via subclassing, virtual methods and garbage collection.

Then, in 1969, Alan Kay started work on Smalltalk. This was a stated attempt to develop a new paradigm in computer programming, one he called object-orientation.

Kay summarized what object-orientation meant to him in an email exchange in 2003:

OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. [Source]

He also passes comment on inheritance, saying:

I didn't like the way Simula I or Simula 67 did inheritance (though I thought Nygaard and Dahl were just tremendous thinkers and designers). So I decided to leave out inheritance as a built-in feature until I understood it better. [Source]

This is interesting when you consider the trajectory mainstream object-oriented languages took in the forty years since the genesis of Smalltalk.

It is doubly interesting when viewed in light of the decisions made during the development of JavaScript.

JavaScript lacked classes at a time when almost all object-oriented languages had them. And here we have the inventor of the paradigm, the best part of a decade after Brendan Eich developed the language, raising no contradiction in terms with being a fully-fledged OO language and the absence of classes.

Furthermore, JavaScript eschewed traditional inheritance, a technology that Kay himself expressed reservations about.

And with the benefit of hindsight, Kay was absolutely right.

Inheritance

Experience has shown that while inheritance is good for object-orientation-101 “a car is-a vehicle” type demonstrations; in the real world it comes with far too great a cost in terms of coupling.

Consider two classes Foo and Bar:

public class Foo {}public class Bar extends Foo {}

Once the inheritance relationship is established between Foo and Bar any change in Foo must consider the impact on all subclasses.

Furthermore, if you wish to inherit from more than one class — a perfectly reasonable request from a data-modelling perspective — then you are presented with a nasty dilemma: either permit multiple inheritance, or develop a byzantine inheritance hierarchy to accommodate it.

Both options introduce significant accidental complexity.

That is not to say that inheritance is always the wrong choice. Occasionally, classical inheritance is very convenient. But it typically works best with hierarchies little more than one level deep.

By way of a note, there is a category of inheritance in strongly-typed languages — interface inheritance — that can be very useful when it comes to modelling systems.

When used as a component of type polymorphism, interface inheritance brings with it many of the benefits of inheritance without the coupling, since interfaces can, by definition, contain no implementation.

JavaScript is of course, not statically typed. It does however have a highly unusual implementation of inheritance based on prototypes.

Whether deliberate or not, this hard-to-understand implementation enabled JavaScript code-bases to sidestep the excesses of classical inheritance prevalent in other languages.

Alternatives

So if not inheritance, what are the alternatives?

Composition is the obvious answer. Objects that contain additional functionality can be injected, rather than relying on the prototype chain.

For most cases this is all you need, although without care it can lead to rather large constructors.

Another option is mixins.

Mixins are methods that are “mixed-in” from one object into another. Indeed the word was originally coined due to the similarity to the mixing of ice-cream flavors.

Mixins also have a more specific kind: traits. Traits are simply mixins but without any associated state. And of course functions are objects in JavaScript, and so can have arbitrary state associated with them.

Examples

The dynamic nature of JavaScript lends itself well to terse implementations of mixins.

Here is a function that will mix methods from a number of objects into an original object, without checking for conflicts.

function mix(original, ...objs) {
objs.forEach(o => {
Object.keys(o).forEach(k => {
original[k] = o[k];
});
});
return original;
}
let foo = {}, bar = {}, result;
foo.a = function() { /*...*/ };
bar.b = function() { /*...*/ };
result = mix({}, foo, bar); // result contains functions a and b

And here is a function that will work with the intent of constructor functions, and place methods on the prototype of a function:

function mix(fn, ...objs) { 
if (typeof fn !== 'function') {
throw 'fn must be a function.';
}

objs.forEach(o => {
Object.keys(o).forEach(k => {
fn.prototype[k] = o[k];
});
});

return fn;
}
function Foo() {}
function Bar() {}
Bar.prototype.a = function() { /*...*/ }
let bam = { b: function() { /*...*/ } };
mix(Foo, Bar.prototype, bam);
let foo = new Foo(); // foo has a and b on its [[Prototype]]

There is one little wrinkle: ES5 getters and setters. How should we deal with them?

Using the techniques so far, the value of a getter — not the property itself — will be copied across to the target. If we want the actual getter or setter function to be copied across we need to be a little cleverer:

function mix(fn, ...objs) { 
if (typeof fn !== 'function') {
throw 'fn must be a function.';
}

objs.forEach(o => {
Object.keys(o).forEach(k => {
var descriptor = Object.getOwnPropertyDescriptor(o, k);
Object.defineProperty(fn.prototype, k, descriptor);
});
});

return fn;
}

Summary

Traditional inheritance brings with it unwanted coupling between hierarchy members. With dynamic object properties and dynamic typing, JavaScript enables a terse implementation of a powerful alternative; mixins.

The downside to this approach is that the result is essentially a hybrid: we lose the ability to trivially reason about the provenance of a mixed-in object.

With this in mind, mixins are another powerful tool to help you design loosely coupled, well-factored software.

My name is Ben Aston and thank you for reading my post today. I am a London-based JavaScript consultant, available for short-term consultancy globally. I can be contacted at ben@bj.ma.

If you would like to further develop your knowledge of JavaScript you might be interested in my hands-on training course. Full details can be found online at www.learnjavascript.london.

If you enjoyed this piece, please let me know by clicking the “recommend” button below.

You may also be interested in my post on closures in JavaScript.

Made in the United Kingdom

--

--