JavaScript Mixins: Beyond Simple Object Extension

Mixins are generally easy in JavaScript, though they are semantically different than what Ruby calls a Mixin which are facilitated through inheritance behind the scenes. If you need a good place to start to understand how to build mixins with JavaScript, Chris Missal has been writing up a series on different ways of extending objects in JavaScript. I highly recommend reading his series. It’s full of great tips.

Object Extension Is A Poor Man’s Mixin

I love the “extend” methods of jQuery and Underscore. I use them a lot. They’re powerful and simple and make it easy to transfer data and behavior from one object to another – the essence of a mixin. But in spite of my love of underscore.js and jQuery’s “extend” methods, there’s a problem with them in that they apply every attribute from one or more source objects to a target objects.

You can see the effect of this in Chris’ underscore example:

In this example, the first object contains a key named “values” and the third object also contains a key named “values”. When the extend method is called, the last one in wins. This means that the “values” from the third object end up being the values on the final target object.

So, what happens if we want to mix two behavioral sets in to one target object, but both of those behavior sets use the same underlying “values”, or “config”, or “bindings” (as reported in this Marionette issue)? One or both of them will break, and that’s definitely not a good thing.

A Problem Of Context

The good news is there’s an easy way to solve the mixin problem with JavaScript: only copy the methods you need from the behavior set in to the target.

That is, if the object you want to mix in to another has a method called “doSomething”, you shouldn’t be forced to copy the “config” and “_whatever” and “foo” and all the other methods and attributes off this object just to get access to the “doSomething” method. Instead, you should only have to copy the “doSomething” method from the behavior source to your target.

But this poses it’s own challenge: the source of the behavior likely calls “this.config” and “this._whatever()” and other context-based methods and attributes to do it’s work. Simply copying the “doSomething” function from one object to another won’t work because the context of the function will change and the support methods / data won’t be found.

[Note: For more detail on context and how it changes, check out my JavaScript Context screencast.]

Solving The Mixin Problem

To fix the mixin problem then, we need to do two things:

  1. Only copy the methods we need to the target
  2. Ensure the copied methods retain their original context when executing

This is easier than it sounds. We’ve already seen how requirement #1 can be solved, and requirement #2 can be handled in a number of ways, including the raw ECMAScript 5 “bind” method, the use of Underscore’s “bind” method, writing our own, or by using one of a number of other shims and plugins.

The way to facilitate a mixin from one object to another, then, looks something like this:

In this example, both the source object and the target object have a “config” attribute. Each object needs to use that config attribute to store and retrieve certain bits of data without clobbering each the other one, but I still want the “baz” function to be available directly on the “foo” object. To make this all work, I assign a bound version of the “baz” function to foo where the binding is set to to the bar object. That way whenever the baz function is called from foo, it will always run in the context of the original source – bar.

A Real Example

Ok, enough “foo, bar, baz” nonsense. Let’s look at a real example of where I’m doing this: Marionette’s use of Backbone.EventBinder. I want to bring the “bindTo”, “unbindFrom” and “unbindAll” methods from the EventBinder in to Marionette’s Application object, as one example. To do this while allowing the EventBinder to manage it’s own internal state and implementation details, I use the above technique of assigning the methods as bound functions:

Now when I call any of those three methods from my application instance, they still run in the context of my eventBinder object instance and they can access all of their internal state, configuration and behavior. But at the same time, I can worry less about whether or not the implementation details of the EventBinder are going to clobber the implementation details of the Application object. Since I’m being very explicit about which methods and attributes are brought over from the EventBinder, I can spend the small amount of cognitive energy that I need to determine whether or not the method I’m creating on the Application instance already exists. I don’t have to worry about the internal details like “_eventBindings” and other bits because they are not going to be copied over.

Simplifying Mixins

Given the repetition of creating mixins like this, it should be pretty easy to create a function that can handle the grunt work for you. All you need to supply is a target object, a source object and a list of methods to copy. The mixin function can handle the rest:

This should be functionally equivalent to the previous code that was manually binding and assigning the methods. But keep in mind that this code is not robust at all. Bad things will happen if you get the source’s method names wrong, for example. These little details should be handled in a more complete mixin function.

An Alternate Implementation: Closures

An alternate implementation for this can be facilitated without the use of a “bind” function. Instead, a simple closure can be set up around the source object, with a wrapper function that simply forwards calls to the source:

I’m not sure if this version is really “better” or not, but it would at least provide more backward compatibility support and fewer requirements. You wouldn’t need to patch ‘Function.prototype.bind’ or use a third party shim or library for older browsers. It should work with any browser that supports JavaScript, though I’m not sure how far back it would go. Chances are, though, that any browser people are still using would be able to handle this, including – dare I say it? – IE6 (maybe… I think… I’m not going to test that, though 😛 )

Potential Drawbacks

As great as all this looks and sounds, there are some limitations and drawbacks – and probably more than I’m even aware of right now.

We’re directly manipulating the context of the functions with this solution. While this has certainly provided a measured benefit, it can be dangerous. There may be (are likely) times that you just don’t want to mess with context – namely when you aren’t in control of the function context in the first place. Think about a jQuery function callback, for example. Typically, jQuery sets the context of a callback to the DOM element that was being manipulated and you might not want to mess with that.

In the case of my EventBinder with Marionette, I did run in to a small problem with the context binding. The original version of the code would default the context of callback functions to the object that “bindTo” was called from. This meant the callback for “myView.bindTo(…)” would be run with “myView” as the context. When I switched over to the above code that creates the bound functions, the default context changed. Instead of being the view, the context was set to the EventBinder instance itself, just like our code told it to. This had an effect on how my Marionette views were behaving and I had to work around that problem in another way.

There certainly some potential drawbacks to this, as noted. But if you understand that danger and you don’t try to abuse this for absolutely everything, I think this idea could work out pretty well as a way to produce a mixin system that really does favor composition over inheritance, and avoids the pitfalls of simple object extension.

Backbone.EventBinder: Better Event Management For Your Backbone Apps