A fresh look at JavaScript Mixins

(Russian, Japanese)

In this article I’ll explore JavaScript mixins in detail, and introduce a less conventional, but to my mind more natural mixin strategy that I hope you’ll find useful. I’ll finish up with a profiler matrix summarizing the performance impact of each technique. [A big Thank You to the brilliant @kitcambridge for reviewing and improving the code on which this blog is based!]

Re-using Functions

In JavaScript, every object references a prototype object from which it can inherit properties. Prototypes are great instruments for re-use: a single prototype instance can define properties for an infinite number of dependent instances. Prototypes may also inherit from other prototypes, thus forming prototype chains which more-or-less mimic the inheritance hierarchies of classical languages like Java and C++. Multi-tiered inheritance hierarchies are occasionally useful for describing the natural order of objects but if the primary motivation is function re-use they can quickly become gnarly labyrinths of meaningless subtypes, frustrating redundancies and unmanageable logic (“is a button a rectangle or is it a control? tell you what, lets make Button inherit from Rectangle, and Rectangle can inherit from Control…wait a minute….”).

Fortunately, when it comes to function re-use, JavaScript offers viable alternatives. In contrast to more rigidly structured languages, JavaScript objects can invoke any public function regardless of lineage. The most straightforward approach is delegation – any public function can be invoked directly via call or apply. It’s a powerful feature and I use it extensively. However delegation is so convenient that sometimes it actually works against structural discipline in your code; moreover the syntax can get a little wordy. Mixins are a great compromise, allowing entire functional units to be borrowed and accessed with minimal syntax and they play very well with prototypes. They offer the descriptive prowess of hierarchical inheritance without the brain-cracking issues associated with multi-tiered, single-rooted ancestry.

The Basics

In general computer science, a mixin is a class that defines a set of functions relating to a type (e.g. Person, Circle, Observer). Mixins classes are usually considered abstract in that they will not themselves be instantiated – instead their functions are copied (or ‘borrowed’) by concrete classes as a means of ‘inheriting’ behaviour without entering into a formal relationship with the behaviour provider.

OK but this is JavaScript, and we have no classes. This is actually a good thing because it means we can use objects (instances) instead, which offer clarity and flexibility: our mixin can be a regular object, a prototype, a function – whatever, and the mixin process becomes transparent and obvious.

The Use Case

I’m going to discuss a number of mixin techniques but all the coding examples are directed towards one use case: creating circular, oval or rectangular buttons. Here’s a schematic representation (rendered using the latest high tech gadgetry). Square boxes represent mixin objects, rounded boxes represent the actual buttons…


 

1. Classic Mixins

Scanning the first two pages returned from a google search for “javascript mixin” I noticed the majority of authors define the mixin object as full-blown constructor type with its function-set defined in the prototoype. This could be seen as a natural progression – early mixins were classes and this is the closest thing JavaScript has to a class. Here’s a circle mixin modeled after that style:

var Circle = function() {};
Circle.prototype = {
  area: function() {
    return Math.PI * this.radius * this.radius;
  },
  grow: function() {
    this.radius++;
  },
  shrink: function() {
    this.radius--;
  }
};    

 
In practice, however, such a heavyweight mixin is unnecessary. A simple object literal will suffice:

var circleFns = {
  area: function() {
    return Math.PI * this.radius * this.radius;
  },
  grow: function() {
    this.radius++;
  },
  shrink: function() {
    this.radius--;
  }
};    

 
the extend function

And how does such a mixin object get mixed into your object? By means of an extend function (sometimes known as augment). Usually extend simply copies (not clones) the mixin’s functions into the receiving object. A quick survey reveals some minor variations in this implementation. For example Prototype.js omits a hasOwnProperty check (suggesting the mixin will have no enumerable properties in its prototype chain) while other versions assume you want to only copy the mixin’s prototype object. Here’s a version that is both safe and flexible…

function extend(destination, source) {
  for (var k in source) {
    if (source.hasOwnProperty(k)) {
      destination[k] = source[k];
    }
  }
  return destination; 
}

 
…which we can call to extend our prototype…

var RoundButton = function(radius, label) {
  this.radius = radius;
  this.label = label;
};

extend(RoundButton.prototype, circleFns);
extend(RoundButton.prototype, buttonFns);
//etc. ...

 
2. Functional Mixins

If the functions defined by mixins are intended solely for the use of other objects, why bother creating mixins as regular objects at all? Put another way, a mixin should be a process not an object. The logical conclusion is to make our mixins into functions into which consumer objects inject themselves by delegation, thus cutting out the middle guy (the extend function) entirely.

var asCircle = function() {
  this.area = function() {
    return Math.PI * this.radius * this.radius;
  };
  this.grow = function() {
    this.radius++;
  };
  this.shrink = function() {
    this.radius--;
  };
  return this;
};

var Circle = function(radius) {
    this.radius = radius;
};
asCircle.call(Circle.prototype);
var circle1 = new Circle(5);
circle1.area(); //78.54

 
This approach feels right. Mixins as verbs instead of nouns; lightweight one stop function shops. There are other things to like here too – the programming style is natural and concise: this always refers to the receiver of the function set, instead of an abstract object we don’t need and will never use; moreover, in contrast to the traditional approach, we don’t have to protect against inadvertent copying of inherited properties and (for what its worth) functions are now cloned instead of copied.

Now here’s a mixin for the button functions…

var asButton = function() {
  this.hover = function(bool) {
    bool ? mylib.appendClass('hover') : mylib.removeClass('hover');
  };
  this.press = function(bool) {
    bool ? mylib.appendClass('pressed') : mylib.removeClass('pressed');
  };
  this.fire = function() {
    return this.action();
  };
  return this;
}; 

 
Put the two mixins together and we’ve got round buttons:

var RoundButton = function(radius, label, action) {
    this.radius = radius;
    this.label = label;
    this.action = action;
};

asButton.call(RoundButton.prototype);
asCircle.call(RoundButton.prototype);

var button1 = new RoundButton(4, 'yes!', function() {return 'you said yes!'});
button1.fire(); //'you said yes!'

 
3. Adding Options

This functional strategy also allows the borrowed behaviours to be parameterized by means of an options argument. Let’s see this in action by creating an asOval mixin with a custom grow and shrink factor:

var asOval = function(options) {
  this.area = function() {
    return Math.PI * this.longRadius * this.shortRadius;
  };
  this.ratio = function() {
    return this.longRadius/this.shortRadius;
  };
  this.grow = function() {
    this.shortRadius += (options.growBy/this.ratio());
    this.longRadius += options.growBy;
  };
  this.shrink = function() {
    this.shortRadius -= (options.shrinkBy/this.ratio());
    this.longRadius -= options.shrinkBy;
  };
  return this;
}

var OvalButton = function(longRadius, shortRadius, label, action) {
  this.longRadius = longRadius;
  this.shortRadius = shortRadius;
  this.label = label;
  this.action = action;
};

asButton.call(OvalButton.prototype);
asOval.call(OvalButton.prototype, {growBy: 2, shrinkBy: 2});

var button2 = new OvalButton(3, 2, 'send', function() {return 'message sent'});
button2.area(); //18.84955592153876
button2.grow();
button2.area(); //52.35987755982988 
button2.fire(); //'message sent'

 
4. Adding Caching

So maybe you’re concerned that this approach creates additional performance overhead because we’re redefining the same functions on every call. With the help of the excellent jsperf.com I ran metrics on every mixin strategy over 4 browsers (you can see the results at the end of this article). Surprisingly Chrome 12 performs significantly better using the functional approach, for the other browsers the functional mixin runs about half as fast as the classic mixin. Given that these mixins are likely to be invoked just once per type definition (as opposed to once per instance creation) the time difference should not cause too much worry, especially since we’re still talking 26,000 mixins per second even in IE8!

However just in case rates like that are keeping your manager up at night, there is a solution. By forming a closure around the mixins we can cache the results of the initial definition run and the performance implications are outstanding. Functional mixins now easily outperform classic mixins in every browser (in my tests by a factor of 20 in Chrome and a factor of 13 in Firefox 4). Again it doesn’t matter much either way but it leaves a nice feeling 😉

Here’s a version of the asRectangle with caching added…

var asRectangle = (function() {
  function area() {
    return this.length * this.width;
  }
  function grow() {
    this.length++, this.width++;
  }
  function shrink() {
    this.length--, this.width--;
  }
  return function() {
    this.area = area;
    this.grow = grow;
    this.shrink = shrink;
    return this;
  };
})();

var RectangularButton = function(length, width, label, action) {
  this.length = length;
  this.width = width;
  this.label = label;
  this.action = action;
}

asButton.call(RectangularButton.prototype);
asRectangle.call(RectangularButton.prototype);

var button3 = 
  new RectangularButton(4, 2, 'delete', function() {return 'deleted'});
button3.area(); //8
button3.grow();
button3.area(); //15
button3.fire(); //'deleted'

 
5. Adding Curry

Everything in life is a trade off and the aforementioned caching enhancement is no exception. We’ve now lost the ability to create true clones for every mixin, furthermore we can no longer customize our borrowed functions by passing option arguments to the mixin. The latter problem can be fixed up by running a curry function over each cached function, thereby pre-assigning custom options to subsequent function calls.

Here’s the asRectangle mixin with functions appropriately curried to allow parameterization of the grow and shrink increments.

Function.prototype.curry = function() {
  var fn = this;
  var args = [].slice.call(arguments, 0);
  return function() {
    return fn.apply(this, args.concat([].slice.call(arguments, 0)));
  };
}

var asRectangle = (function() {
  function area() {
    return this.length * this.width;
  }
  function grow(growBy) {
    this.length += growBy, this.width +=growBy;
  }
  function shrink(shrinkBy) {
    this.length -= shrinkBy, this.width -= shrinkBy;
  }
  return function(options) {
    this.area = area;
    this.grow = grow.curry(options['growBy']);
    this.shrink = shrink.curry(options['shrinkBy']);
    return this;
  };
})();

asButton.call(RectangularButton.prototype);
asRectangle.call(RectangularButton.prototype, {growBy: 2, shrinkBy: 2});

var button4 = new RectangularButton(2, 1, 'add', function() {return 'added'});
button4.area(); //2
button4.grow();
button4.area(); //12
button4.fire(); //'added'

 
Performance Metrics

As promised, here’s a summary of my jsperf tests, matrixed by technique and browser.
Remember the results are in thousands of operations per second, so high numbers are good.


 

Wrap Up

JavaScript is an amalgam of function and state. State is generally specific to instances, while functions will almost certainly be shared across instances. Maybe it’s in our interest to separate these two most basic concerns and maybe mixins can help us do this.

In particular the functional mixin pattern offers a clear delineation. Objects are state while functions are organized in bunches like fruit on a tree, ripe for picking. In fact the strategy can be extended beyond pure mixins – functional sets can act as repositories for any object…

var myCircle = asCircle.call({radius:25});
myCircle.area(); //1963.50

Have fun exploring mixins, and as always please let me know of corrections and other feedback!

84 thoughts on “A fresh look at JavaScript Mixins

  1. This is an interesting approach. I’ve been using traditional mixins (with the extend helper around). I really like the way you described it: “a mixin should be a process not an object”. The one thing which concerns me is the fact that the mixin functions are redefined on every call now (which you addressed with the closure and caching).

  2. Great post. I really like the idea of a mixin being a verb rather than a noun – i.e. something you do to an object. It’s nice to see such a range of approaches.

    One thing though: not sure I’d agree with what you call the “revealing module pattern” – to me that’s where you return an object, e.g. return { area: area, grow: grow, shrink: shrink}; or something like that. I know it’s basically doing the same thing, and there’s probably not a name for what you’re doing there! I’d probably say something like “a modified revealing module pattern” though. Sorry, pedantry over 😛

  3. @Michal – glad you like it! Remember even the non cached version should not cause a performance headache – when applied to prototypes, the mixin pattern will only be applied rarely (when constructors/types are initially defined) and in total probably no more than a handful of times. Also there are benefits to redefining the function – it ensures each prototype gets a unique version of a function which is useful if you want to parameterize their definitions. But I take your point and you should go with what works for you.

    @Skilldrick – thanks! Yeah you’re right – put it down to a senior moment, This is really just the regular module pattern (though with a twist because it returns a function not a regular object). I edited the article to remove any trace 😉

    1. @autre, thanks for the nice words!
      Yes traits are sort of a logical progression from the custom mixins I started exploring in this article. There is power in their flexibility/intelligence although the implementation must be kept as simple as possible

  4. Good article. At first understandable and easy, but it get’s more difficult while your read (or maybe I felt so). I think mixin is a non-deductional term and an MDT (more deductional term) for it could be commons or something like that. As much as I know about them, they are only common behaviors or functionalities (common properties or common methods) that let you use them anywhere. With this definition, mixins are not interfaces (as they are not contracts), and they are not base abstract classes (as the relationship is not is-a). They are has-a relationship.
    Anyway, let’s support CSS3. Read CSS3 Multi-Column Layout Module and CSS3 Animations and have a look at css animations at My heart beats using latest version of Google Chrome.

  5. Very nice article!! Thx!! The JSPerf test is showing that the caching method is way faster than the other mixins methods. But the caching mixin method, though faster, doesn’t generate the fastest class in the end (instantiation & method call slower, see http://jsperf.com/mixin-fun/4) Shouldn’t we use the mixin method that generates the fastest class?

    1. Hi Jie – thanks for the feedback. You’re tests are now measuring object instantiation not mixin time. The first 3 cases are actually identical. The differences are arbitrary – I created a new test http://jsperf.com/mixin-fun/5 which switches the order of your first two tests -now the new style instantiation is quicker!

      1. Thanks for the clarification! Indeed, same prototype, same perfs. Strange that jsperf behaves so differently just by switching the order of the tests. I’m asking @jdalton about this!

  6. Did you see Jie’s revision of the jsperf tests? http://jsperf.com/mixin-fun/4

    He moved the extend functionality into the preparation of CircularObject1 (because you don’t need to extend CircularObject1 every time you instantiate it)

    Now the “old style” becomes the fastest.

    1. Yeah, Jie’s test measures instantiation time, not mixin time – so the mixin code can be removed from every test (old and new style). Now the first 3 cases are identical (all 3 prototypes are the same) so the results are arbitary

      In fact you can switch test 1 with test 2 as I did (http://jsperf.com/mixin-fun/5) and new style instantiaton now appears faster!

  7. Dear Author,

    You are sick! This was an awesome blog! Great job at explaining in detail, and explaining clearly for non-Sr-JS readers.


    AF

  8. This is a really good post, these approaches are pretty cool. I agree that the processing cost is usually trivial with instantiation. However, I would be concerned about the memory overhead with some of these mixin patterns. It’s my understanding that taking any approach other than “true” prototypal inheritance makes a copy (in memory) of each method that gets mixed-in/inherited.

    I suppose the best solution depends on a lot of factors. For most applications, the approaches you describe are elegant and offer more than enough performance. For certain situations, such as making a game or a page that never refreshes (Gmail), it pays to watch memory consumption and optimize function reuse.

    1. Thanks Jeremy. Just to clarify, in all the strategies I discuss, the developer is free to pass a prototype as the mixin context – in fact in all my examples (except the one in the wrap up) that’s exactly what happens – so there is zero loss in instantiation performance. Put it another way, using the classic versus the functional technique does not predicate use of prototypes.

  9. Thanks for the article. Here’s one criticism.

    Eliminating “extend” seems overly minimalist. By using “call” directly, you’ve let a low-level tool bubble up into high-level code.

    extend(RoundButton.prototype, circleFns);
    asCircle.call(RoundButton.prototype);

    1. Hi Eric. My point was less about syntax than process. The old extend was a somewhat tedious copy process. The new technique eliminates the copy step. If you’re uncomfortable with call you could wrap it in extend:

      function extend(fn, obj) {
        fn.call(obj);
      }
      
  10. Nice one, it is a shame that JS has single inheritance _and_ poor object enumeration. The so-called “old-style” approach does have the advantage of being predictable, extendable(ish), and not entering functions in triplicate.

    I added a snippet (http://jsperf.com/mixin-fun/10) with a utility that precompiles a “caching” copier for a regular object. Also! jsperf was sharing the same prototype between tests.

    1. Oh good call! I missed the fact that I was not resetting the prototype each time – this inevitably adds a little more latency to later tests.

      Fixed now
      http://jsperf.com/mixin-fun/12

      BTW not sure what you mean about old-style being more predictable, extendable(ish), and not entering functions in triplicate. New-style is all of those things

      Thanks for adding another test – I’ll take a proper look when I get a chance.

      1. Don’t get me wrong. I like the idea of mixin/extension/instantiation as a function. But we are defining “methods” here, so if the mixins look like prototypes, i.e., plain objects, that’s going to be less unexpected, though unexpected may be what you’re going for. I can’t really elaborate more on that point.

        Since the methods have to be copied to the target class, neither method is going to support “live” extensions, but if you wanted to support plugins, say, it’s a bit easier to have methods attached to an object than, I suppose, wrapping the mixin function to get additional functionality.

        And as you demonstrated, re-using the same functions required you to close over another function which had to essentially repeat the function names another two times to work.

  11. Hey Man
    Very inspiring post. A colleague an I liked it so much we did a thing similar to Douglas Crockfords Object.Create:
    if (typeof Object.prototype.addMixin !== ‘function’) {
    Object.prototype.addMixin = function (mixin) {
    mixin.call(this.prototype);
    };
    }

    This way we can write:
    RoundButton.addMixin(asButton);
    RoundButton.addMixin(asCircle);

    Which reads nicely

    http://jsfiddle.net/khebbie/4ZkSZ/10/

    1. I like it! My only addition would be that since you are extending Object.prototype, you should probably make sure to mark addMixin as not enumerable:

      if (typeof Object.prototype.addMixin !== ‘function’) {
      Object.defineProperty(Object.prototype, ‘addMixin’, {
      value: function addMixin(mixin) {
      mixin.call(this.prototype);
      },
      configurable: true,
      writable: true
      });
      }

    1. @nick totally agree – in fact I nearly called it mixin decorators. Bottom line is it probably help to think of mixins as decorators not agents of multiple inheritance

  12. What’s the curry function doing with those arrays?

    Function.prototype.curry = function() {
      var fn = this;
      var args = [].slice.call(arguments, 0);
      return function() {
        return fn.apply(this, args.concat([].slice.call(arguments, 0)));
      };
    }
    

    Can you explain this a bit more? It seems like your slicing an empty array and then joining it again?

    1. Hi Vince

      The curry function is a function that returns another function. The first reference to arguments is the arguments object of the curry function, the second is the arguments object of the returned function. The concat is joining the two arguments objects together.

      The purpose of [].slice.call(arguments, 0) is to convert the arguments object (which is not a true array) into an array so that concat can be invoked on it. This works by invoking the native array slice method ([].slice) on the arguments object starting from index 0. The result is the arguments object converted to an array

  13. Great article. I’m thinking about using mixins when developing a small UI framework for the company I work for.

    Having the ability to make a Button be an Observable, and a Component (which means it has a UI representation) at the same time is awesome. However, Component would be an Object… and that’s the place where I get stuck.

    Object has the init function.
    Component should call Object init.
    Button should call init funciton from Component which calls init form Object.
    Button also calls initEvents from Observable.

    Not sure if it makes any sense 🙂

  14. Pingback: Quora
  15. Great article. I have one question re: the final implementation – what if you want to access the mixin methods – are they locked in by the closure? If I want to update one of the methods can I do it? With simple prototype inheritance I can edit the prototype at any time and affect all instances. Here it seems difficult to do that:

    asRectangle.grow // no
    asRectangle.prototype.grow // no
    RectangularButton.prototype.grow // yes, but curried version

  16. Pingback: Ember.js Days
  17. Very interesting. But wouldn’t it be better if state AND behaviour were part of the mixin ? The problem I see in your method is that you created an implicit dependency between a mixin and the instance properties needed to run the mixin’s functions. Said another way, the `asRectangle` can’t work if the object it’s extending doesn’t have the `length` and `width` properties. I’d find a mixin even better if everything necessary was encapsulated in one place. I’m implicitly referring to the Component-Entity-System architecture often used in video-games but that can be applied to other use cases.
    PS : of course such a system shouldn’t attach instance properties to the prototype and vice-versa.

    1. Sure, sometimes it makes sense for a mixin to define state – in the case that such state is particular to the behavior being mixed in. In the case of mixing a rectangle into a button, we are assuming that the target object is already suitably shaped – and has width and height properties. It would not make sense to redefine width and height when the button already has those properties

      It’s a murky line – ideally we want the mixin to be agnostic of its target object, but on the other hand mixins must be complementary, not clobbermentary 🙂

      At twitter we use advice (before, after and around) to allow mixin functions to complement those of the target object without clobbering them (or even having to know of their existence). A somewhat similar idea could be applied to state properties

    2. It depends on what the abstraction is supposed to achieve. Since the Flight Mixin pattern is function based, it does provide delegation for free and also enables injecting of and passing around additional state. Some variants of this pattern then might act more like Traits.

      Reading about [“The many talents of JavaScript for generalizing Role Oriented Programming approaches like Traits and Mixins”](http://peterseliger.blogspot.de/2014/04/the-many-talents-of-javascript.html#the-many-talents-of-javascript), might add a new perspective to this matter and could revitalize discussions and renew perception triggerd by Angus’ already “classical essay”.

  18. No, I take that back. There is method overriding if we use functions, but not when using this in conjunction with Simple Javascript Inheritance.

  19. Excelent post. Not to be nitpicking but wouldn’t be more expressive to have
    var CircleBehaviour = function() {/*… */}
    CircleBehaviour.apply(Button.prototype);

    Also, the “shrinkBy” example seems to me a little counter-intutitive because the “shrinkBy” looks like it should be a property of the button, like “radius” is for circle. On the other hand I understand that would be more difficult to create customizable functional mixins by including “configuration” properties.
    var CircleBehaviour = function() {
    this.shrinkBy = 2;
    this.shrink = function() {/* …. */}
    };
    would require using the “old” mixing
    extend(CircleBehaviour, {shrinkBy: 5}).apply(Button.prototype);

    How would you go about using ONLY functional mixin in this situation?

  20. This curry function is a poison man!
    Your functional mixin pattern is very cool, but the curried options is not a often case and is expensive.
    But even if you really need to use it, I advise you to use a simple pattern of curry.
    As you can see in my revision of jsperf (http://jsperf.com/mixin-fun/34), the result was improved, going to the 3rd position of ops/sec.

  21. I was just refactoring some code to use mixins and realized I couldn’t do the simple object extend method because I was mixing in KO observables, so I thought to make mixins as functions, and lo and behold, you have a great writeup on why that’s a good idea. I opted for a different signature for my mixin functions, though: function DateMixin(self)

  22. Why are we using call rather than just passing the prototype as a parameter?

    ie.

    var mixinRectangle = (function() {
    function area() {
    return this.length * this.width;
    }
    return function(obj) {
    obj.area = area;
    return obj;
    };
    })();

    mixinRectangle(RectangularButton.prototype);

    1. Hi Gabriel

      Either case is valid. I use call so that `this` becomes the placeholder for the target object. Yes you could pass the placeholder as an argument instead. My preference for the first technique is

      1) `this` is immutable, which prevents the target object from being accidentally updated
      2) If additional arguments are passed, with the second technique these are not clearly distinct from the placeholder argument

      Hope this helps

Leave a comment