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:

var start = {
    id: 123,
    count: 41,
    desc: 'this is information',
    title: 'Base Object',
    tag: 'uncategorized',
    values: [1,1,2,3,5,8,13]
};
var more = {
    name: 'Los Techies',
    tag: 'javascript'
};
var extra = {
    count: 42,
    title: null,
    desc: undefined,
    values: [1,3,6,10]
};

var extended = _.extend(start, more, extra);
console.log(JSON.stringify(extended));
{
    "id": 123,
    "count": 42,
    "title": null,
    "tag": "javascript",
    "values": [1,3,6,10],
    "name": "Los Techies"
}

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.

var foo = {
  doSomething: function(){
    // ...
  }
}

var bar = {};
bar.doSomething = foo.doSomething;

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:

var foo = {
  baz: function(){ 
    // ...
  },

  config: [ ... ]
}

var bar = {
  config: { ... }
};

// ECMAScript "bind"
bar.baz = foo.baz.bind(foo);

// Undescore "bind"
bar.baz = _.bind(foo.baz, foo);

// ... many more options

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:

Marionette.addEventBinder = function(target){

  // create the "source" of the functionality i need
  var eventBinder = new Marionette.EventBinder();

  // add the methods i need to the target object, binding them correctly
  target.bindTo = _.bind(eventBinder.bindTo, eventBinder);
  target.unbindFrom = _.bind(eventBinder.unbindFrom, eventBinder);
  target.unbindAll = _.bind(eventBinder.unbindAll, eventBinder);
};



// use the mixin method
var myApp = new Marionette.Application();
Marionette.addEventBinder(myApp);

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:

// build a mixin function to take a target that receives the mixin, 
// a source that is the mixin, and a list of methods / attributes to
// copy over to the target

function mixInto(target, source, methodNames){

  // ignore the actual args list and build from arguments so we can
  // be sure to get all of the method names
  var args = Array.prototype.slice.apply(arguments);
  target = args.shift();
  source = args.shift();
  methodNames = args;

  var method;
  var length = methodNames.length;
  for(var i = 0; i < length; i++){
    method = methodNames[i];

    // bind the function from the source and assign the
    // bound function to the target
    target[method] = _.bind(source[method], source);
  }

}


// make use of the mixin function
var myApp = new Marionette.Application();
mixInto(myApp, Marionette.EventBinder, "bindTo", "unbindFrom", "unbindAll");

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:

// build a mixin function to take a target that receives the mixin, 
// a source that is the mixin, and a list of methods / attributes to
// copy over to the target

function mixInto(target, source, methodNames){

  // ignore the actual args list and build from arguments so we can
  // be sure to get all of the method names
  var args = Array.prototype.slice.apply(arguments);
  target = args.shift();
  source = args.shift();
  methodNames = args;

  var method;
  var length = methodNames.length;
  for(var i = 0; i < length; i++){
    method = methodNames[i];

    // build a function with a closure around the source
    // and forward the method call to the source, passing
    // along the method parameters and setting the context
    target[method] = function(){
      var args = Array.prototype.slice(arguments);
      source[method].apply(source, args);
    }

  }

}


// make use of the mixin function
var myApp = new Marionette.Application();
mixInto(myApp, Marionette.EventBinder, "bindTo", "unbindFrom", "unbindAll");

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 :P )

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.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in ECMAScript, Javascript, Marionette, Principles and Patterns, Underscore. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Trisha Sue

    Thanks for this post. It made me understand JavaScript ixins a lot better.

  • Eric Elliott

    Nice work on this. I use a similar technique in applitude.js to allow users to trigger events on a global eventEmitter using shortcuts on the app object: app.on() maps to app.events.on(), etc… I really like your closure implementation of mixInto().

    http://ericleads.com/2012/08/introducing-applitude-simple-module-management/

  • Ruben Vreeken

    I think in some cases this could also be interesting in combination with a facade. Lets say your component is actually always intended to be a mixin.

    You could expose the methods you want to mix into the target through the facade and keep the things you don’t want to mix in private.

    That way the component is in control of which methods get mixed in, rather then requiring a developer to manage this manually.

  • http://twitter.com/p3drosola Pedro Solá

    I think you’ve misunderstood the whole point context binding.

    If you pluck a function from another object and maintain it’s original context, you’re just creating an alias. Not terribly useful, it’s just syntax suger.

    The interesting thing is usually to pluck a function from an object, and bind it to another.

    For example, (and this is specifically the use-case you discourage) a jQuery callback.
    How do do imagine Backbone’s declarative events get bound to the view?

    $(this.el).on(‘click’, ‘.delete’, _.bind(this, someObject,clickhandler));

    so clickHander can call this.model.delete(), for example.

    Have you even read the source of underscore’s bind method? It’s like 10 lines. Not complicated at all.

    No offense, but this article is spreading some serious mis-information. I feel should warn those unfamiliar with the subject to do make sure they get their facts straight.

  • Kevin

    Derick,

    Interesting post, thanks. It seems like the approach here is to only mix in public methods, and if there is internal state that needs to be maintained, that they not be maintained on the target class. Seems like a good idea, so that you can avoid conflicts on the target class. Although doing this by manipulating the function’s context does prevent your mixin functions from using other functionality on the target class, although maybe this is intentional?

    And if I’m reading it correctly, your first implementation here would pollute the source mixin object:

    //Dummy mixin implementation

    var CoolMixin = {

    bindTo: function(args) {

    this._bindings || (this._bindings = []);

    this._bindings.push(args);

    },

    getBindings: function() {

    return this._bindings;

    }

    };

    var A = new Backbone.View({});

    var B = new Backbone.View({});

    mixInto(A, CoolMixin, ‘bindTo’, ‘getBindings’);

    mixInto(B, CoolMixin, ‘bindTo’, ‘getBindings’);

    //Now let’s bind A and B to events on C

    var C = new Backbone.Model({});

    //This has the effect of applying CoolMixin#bindTo in the context of CoolMixin, thus adding a _bindings property to CoolMixin.

    A.bindTo(C, ‘change’, A.render);

    //And since the CoolMixin methods on B are also bound to the same source, B now has A’s bindings.

    console.log(B.getBindings());

    //And if we bind B to another event, A gets them as well

    B.bindTo(C, ‘change’, B.render);

    console.log(A.getBindings());

    And I believe the second implementation of mixInto is missing a return statement near the end and should read:

    return source[method].apply(source, args);

    If you’re trying to avoid maintaining state on the target object, you lose the simplicity of the object literal literally getting mixed in. At that point you may as well just make another standalone object to track the mixin’s state. This is something we’ve done in similar circumstances when there’s a lot of state to track, and I think is similar to your approach with the EventBinder, except it explicitly passes the state object instead of passing it through the function context. With this approach, you have a plain object literal mixin that mixes in some sort of initialization method onto the target class, and that initialization method creates a separate object to manage any state that the mixin needs to maintain, as well as mixes in any additional functionality. This approach also lets you be really careful (if you want to be) and even add a check at runtime for whether the mixin would overwrite an existing method. Like this:

    //Utility function for getting all properties on an object, including ones set on its prototype chain

    var allKeys = function(obj) {

    var keys = [];

    for (var prop in obj) { keys.push(prop); }

    return keys;

    };

    //Dummy mixin implementation

    var CoolMixinLazy = {

    initCoolMixin: function() {

    //Mixin state gets closed over here

    //You can imagine this using a whole other object rather than just an array if needed.

    var bindings = [];

    var methods = {

    bindTo: function(args) {

    bindings.push(args);

    },

    getBindings: function() {

    return bindings;

    }

    };

    //Optional run time check for collisions, or possibly chaining

    //methods together (e.g., Backbone.Model#validate)

    var collisions = _.intersect(_.keys(methods), allKeys(this));

    console.log(_.keys(methods), _.keys(this), collisions);

    if (!_.isEmpty(collisions)) throw new Error(‘collision trying to mix in: ‘ + collisions.join(‘, ‘));

    //Mix in and return this for chaining

    _.extend(this, methods);

    return this;

    }

    };

    var LazyView = Backbone.View.extend(CoolMixinLazy);

    var D = new LazyView({});

    D.initCoolMixin();

    //detecting collisions

    var DifferentView = Backbone.View.extend({ getBindings: ‘there are none!’ });

    var LazyDifferentView = DifferentView.extend(CoolMixinLazy);

    var E = new LazyDifferentView({});

    E.initCoolMixin();

    Personally, almost all of this is overkill for me, which is why I mostly keep using the object literal approach and storing any object state on the target object, just with weirder names than _bindings. Maybe not the best long term strategy, but seems the simplest to me for the moment. :)

    -Kevin

    • Kevin

      Sorry about the formatting…

    • http://mutedsolutions.com Derick Bailey

      correct on all counts. :)

      this was a very naive implementation, meant to be an illustration of an idea, and not really production ready code.

      regarding the need to access the target object from the mixin – yeah, this has been the largest problem i’ve encountered in trying out these ideas in real code. i have some ideas for getting around that, but it all involves more code than i like.

      i think there’s value in this idea, still. but it will need to be fleshed out in to something that is easy to use and provides real value without a lot of overhead.

  • Sara Lisa

    Hi Bailey! this was unique. the logic used really helped me in many ways. there is always a challenging life for programmers. thanks Business Objects Online Training

  • omouse

    Why do I feel like everything in JavaScript and all the frameworks are craaaazy to understand…this coming from a Scheme/Lisp coder too, I’ve even handled some Smalltalk.

    • http://mutedsolutions.com Derick Bailey

      because they are!

      most languages bake the complexity in to the language, but JavaScript has been notoriously behind the curve on that. it’s so dang simple, but so open and flexible at the same time. it allows a seemingly simple set of rules to become very complex in implementation, very quickly.

      but it lets us build some awesome apps, and there are even times when the language structure fits the nature of the system being built, too. i certainly love my javascript, but i don’t think it’s without fault by any means :)

  • LarryQ

    Thanks for the article.
    Maybe I’m missing it, in which case sorry upfront, but is this part correct?

    “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”

    Shouldn’t ‘foo’ be the context in that snippet, not ‘bar’?