Book Image

Backbone.js Patterns and Best Practices

By : Swarnendu De
Book Image

Backbone.js Patterns and Best Practices

By: Swarnendu De

Overview of this book

Table of Contents (19 chapters)
Backbone.js Patterns and Best Practices
Credits
About the Author
Acknowledgments
About the Reviewers
www.PacktPub.com
Preface
Precompiling Templates on the Server Side
Index

Understanding JavaScript mixins


In the previous section, we saw that inheriting properties from a parent class prototype provides a great deal of reusability. In some cases, we may want to re-use similar methods in multiple views, models, or collections. This can be achieved by creating a parent class that they can extend; however, it is not always a good practice as it creates some unnecessary layers and meaningless subtypes.

For example, assume that you want the view element of UserItemView, which already extends BaseView, to be draggable. So you include a DraggableView class that extends the BaseView class, and your UserItemView extends DraggableView. Now there is a sudden change in the requirement and you are asked to make the view named UserItemView a sortable view as well. Will you introduce another new class, SortableView, and put it somewhere in the chain? If yes, then this multitiered inheritance will surely create a logic that is absolutely unmanageable and frustrating. Look at the following figure that describes the situation in a better way:

What is a mixin?

Fortunately, there is a feasible alternative in JavaScript, which is called m ixin. In general computer science, a mixin is a class that provides a set of functions relating to a particular type. These mixin classes are not instantiated, but their functions are just copied to the main class to achieve a similar inheriting behavior without entering into the inheritance chain. Look at the following figure to understand the concept:

We have a ListItemView class that extends the BaseView class and represents an individual item of a list. Now we want these items to be draggable. How we can achieve this? How about adding a few methods in the ListItemView class that will take care of the dragging functionality? This approach will work, but what if we have few more components that need to be draggable too? Then we have to make a reusable object with these methods and use that object in all the required classes. This is what the mixin concept is—a collection of methods that will be copied to the class that wants this functionality.

Creating classic mixins

The most basic mixin definition will be a simple object with some properties such as the following code snippet:

// A simple object with some methods
var DraggableMixin = {
  startDrag: function () {
    // It will have the context of the main class 
    console.log('Context = ', this);
  },
  onDrag: function () {}
}

// UserItemView already extends BaseView
var UserItemView = BaseView.extend({
  tagName: 'div',
  template: '<%= name %>'
});

We will use the Underscore method, _.extend(), to copy the mixin properties to the main class's prototype:

// We just copy the Mixin's properties into the View
_.extend(UserItemView.prototype, DraggableMixin, {
  otherFn: function () {}
});

var itemView = new UserItemView();

// Call the mixin's method
itemView.startDrag();

Note that the drag-related methods are now copied from DraggableMixin to its prototype. Similarly, we can use the same _.extend() method to copy the methods of SortableMixin to implement the sortable behavior without creating any multilayered inheritance.

Sometimes you may not want to copy all the methods of a mixin in your class. In that case, simply create a property in your class and copy the required function from the mixin in that property:

UserItemView.prototype.startDrag = DraggableMixin.startDrag;

This is helpful when you need only a part of the functionality from the mixin.

Creating functional mixins

There are some other ways of defining a mixin too. The following is an example of a functional pattern:

// Functional mixin
var DraggableMixin = function (config) {
  this.startDrag = function () {};
  this.onDrag = function () {};

  return this;
}

// DraggableMixin method is called passing the config object 
DraggableMixin.call(UserItemView.prototype, {
  foo: 'bar'
});
// SortableMixin.call(UserItemView.prototype);

new UserItemView().startDrag();

The mixin here works as a verb, and this functional approach is well accepted in the community. The this function always refers to the receiver, that is, UserItemView. The functionality is exactly same but with a major difference—the _.extend() method is no longer needed and the mixin methods are not copied this time but are cloned instead. This is not a major problem—just the functions are redefined every time the mixin is used. However, this can also be minimized by caching the functions within the mixin. Let's see how we can achieve that in the next section.

Caching mixin functions

We can cache the initial function definitions by wrapping up the mixin in a closure:

// Functional mixin with cache
var DraggableMixin = (function () {
  var startDrag = function () {};
  var onDrag = function () {};

  return function (config) {
    this.startDrag = startDrag;
    this.onDrag = onDrag;

    return this;
  };
})(); 

The closure executes only once to define the methods even if the mixin is called several times. However, it raises another concern—inside the mixin methods, how are we going to use the config object that we are passing? This issue can be resolved by using an interesting pattern named curry.

Using curry to combine a function and arguments

As described by Douglas Crockford in his book Javascript: The Good Parts:

"Currying allows us to produce a new function by combining a function and an argument."

Assume that you have a function and a set of arguments. You want these arguments to be combined with the function someway, so that when you will call that function without passing anything, the arguments will still be available to the function. See the following example:

// Simple function
function foo(){
  console.log(arguments);
}


// We want this bar object to be available in the foo() function
var bar = {
  name: 'Saswata Guha'
};

// Calling foo() without passing anything. Using curry, the 
// function will have the bar object in its scope
foo();  

The curry() pattern's definition is quite simple where this method is added to the function prototype, so when it is called on any function, it merges the arguments passed to itself with the arguments of the main function, as shown in the following code snippet:

// Definition of curry
Function.prototype.curry = function () {
  var slice = Array.prototype.slice,
    args = slice.apply(arguments),
    that = this;
  return function () {
    return that.apply(null, args.concat(slice.apply(arguments)));
  };
};

Now let's see how we can apply curry to our DraggableMixin function, so that the config object is available to all its methods, as shown in the following code snippet:

// Functional mixin with cache
var DraggableMixin = (function () {
  var startDrag = function (options) {
    console.log('Options = ', options);
  };
  var onDrag = function () {};

  return function (config) {
    this.startDrag = startDrag.curry(config);
    this.onDrag = onDrag;

    return this;
  };
})();

DraggableMixin.call(UserItemView.prototype, {
  foo: 'bar'
});

So, when we call curry on the startDrag() method, we pass the config object that we received while applying mixin, and it becomes available to startDrag as an argument. You can use either the classic or functional approaches for defining a mixin, though I personally prefer the latter.

Mixin is an important concept that many popular JavaScript libraries such as Sencha and Dojo follow. While the concept is quite easy, finding a proper context in an application to use a mixin is bit difficult. However, once you are aware of its use, you may soon find it beneficial to enforce reusability in your application.