Mixin

A way to dynamically add functionality to an object.



Usage in JavaScript:
medium high


Fundamentals


The Mixin pattern allows adding functionality to an object. Before getting into mixins lets review which JavaScript patterns exist to extend functionality to objects. They are: 1) Prototypal Inheritance, 2) the Extend Pattern, and 3) the Mixin Pattern. We will discuss each of these.

Prototypal Inheritance
Prototypal inheritance is JavaScript's out-of-the-box inheritance model. If you are coming from a language such as C++, C#, Java, or PHP, you are familiar with class based inheritance in which classes derive functionality from ancestor classes. As you know, JavaScript does not support classes, but it does offer an object-based inheritance model called prototypal inheritance.

As discussed in the Essentials section, a prototype is an object from which other objects inherit functionality. Each object has a prototype. Prototypes themselves have prototypes, leading to prototype chains. Each object has a built-in internal property, called __proto__ (or [[Prototype]]), which references its prototype object.

In Prototypal inheritance objects inherit from other objects. Suppose you have an object with some properties and methods and you wish to reuse this functionality. At runtime, you can do this by setting the derived object's prototype property to an instance of the first object, like so:

// helper function

function inherit(source) {
    function F() {};
    F.prototype = source;
    return new F();
}

var person = { 
    color: "brown",
    say: function () {
        alert("Hi, I have " + this.color + " eyes");
    }
};

var employee = inherit(person);
employee.salary = "$35,000";

employee.say();            // => Hi, I have brown eyes

Run

For now, ignore the inherit function which will be discussed shortly. First, a person with brown eyes is created. Then a new employee object is created that inherits from person. This employee has a salary of $35,000. The last line confirms that employee indeed inherited both the color and say members from the person object.

The inherit function is a helper that creates a new object with its prototype property pointing to the incoming source, or ancestor, object. It creates a new object that is derived from the incoming ancestor object. This function may seem a bit odd, but when you go line by line you will see it is not overly complex. First, an empty constructor function F is created (it is capitalized, as all construction functions should be). Its prototype property is assigned the ancestor object. Finally, we return a new instance of F, which is empty but with its prototype pointing to the ancestor object. By the way, the inherit function is something you may encounter in other libraries where it may have names like beget or object.

We should mention that this kind of ad hoc prototypal inheritance is unusual because prototypal inheritance relationships are mostly established by constructor functions and their prototype settings. We will see examples of this in this program.

Extend Pattern
The second pattern we examine is the Extend Pattern. This pattern is widely used and is available in many JavaScript frameworks and libraries. It inherits functionality by copying properties from one object into another. Here is how it's done:

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

var person = { 
    color: "blue",
    say: function () {
        alert("Hi, I have " + this.color + " eyes");
    }
};

var employee = { salary: "$35,000" };

extend(person, employee);   // the extend pattern

employee.say();             // => Hi, I have blue eyes

Run

Skip the extend method for now. It is discussed in the next paragraph. A person object is created with the color blue and a say method. Next we create an employee object with a salary property. The extend function copies the members from a source object to a destination object, in this case from a person to an employee. At the end we confirm that employee indeed has all members (properties and methods) copied from the person object.

The extend method gets passed a source object and a destination object. Using a for-in loop it iterates over all properties on the source and copies these over to the destination. Using the built-in hasOwnProperty method we check whether the property is on the object itself or on its prototype. Only properties on the object are copied over.

This version of extend performs what is called a shallow copy. It does not copy properties that are objects or arrays themselves. Instead, it copies their references and that is usually not what you want.

To make true copies of properties that are objects and arrays we need to recursively call extend for each object and array property. This process is called deep copy. Here is the code that will do just that:

function deepExtend(source, destination) {
    for (var s in source) {
        if (source.hasOwnProperty(s)) {
            if (typeof source[s] === "object") {
                destination[s] = isArray ? [] : {};
                deepExtend(source[s],destination[s]); 
            } else {
               destination[s] = source[s];
            }
        }
    }
    function isArray(o) {
        return (typeof o === "[object Array]");
    }
}

var person = {
    name: "Karen",
    address: {
       street: "1 Main St",
       city: "Baltimore"
    },
    scores: [212, 310, 89],
    say: function () {
         alert(this.name + ", " + this.address.street + ", " +
               this.address.city + ", " + this.scores );
    }
};
var employee = { salary: "$45,000" };
deepExtend(person, employee);

employee.say();  // => Karen, 1 Main St, Baltimore, 212, 310, 89

Run

Like extend, the function deepExtend iterates over the properties of the source object. However deepExtend includes a property type check for type object. If true, we have an object or an array. The isArray helper method tells us if this is an array or not. If it is an empty array property gets added to destination, otherwise an empty object. The deepExtend is then recursively called which will copy the object or array. Note that function objects are still copied by reference which is preferable because it saves memory.

The person object is a complex object with multiple member types: a primitive property, an object property, an array property and a function object property (i.e. method). The function deepExtend successfully copies all these from person to employee (source to destination). We confirm this by invoking the say method which displays all person properties.

Mixin Pattern
The Mixin pattern goes one step further in that it copies properties from one or more source objects. All properties get 'mixed' together in this new object. Here is an example of an array of employees. The mixin function copies properties from two objects into the array object: sortable and enumerable, which add sorting and enumeration functionality to the array.

function mixin(sources, destination) {
    for (var i = 0, len = sources.length; i < len; i++) {
        var source = sources[i];
        for (var s in source) {
            if (source.hasOwnProperty(s)) {
                destination[s] = source[s];
            }
        }
    }
}

var Employee = function (name, gender, age) {
    this.name = name; 
    this.age = age; 
    this.gender = gender;
}

var employees = [];

employees.push(new Employee("John", "Male", 33));
employees.push(new Employee("Peter", "Male", 45));
employees.push(new Employee("Ann", "Female", 32));
employees.push(new Employee("Tiffany", "Female", 19));

var sortable = {
    sortAge: function () {
        this.sort(function (a, b) {
            return a.age - b.age;
        });
    }
};

var enumerable = {
    each: function (callback) {
        for (var i = 0, len = this.length; i < len; i++) {
            callback(this[i]);
        }
    }
};

mixin([sortable, enumerable], employees);

employees.sortAge();
employees.each(function (item) {
    alert(item.name + " " + item.age);   // => Tiffany 19, Ann 32, 
                                         //    John 33, Peter 45   
});
Run

This example is very interesting. First off, the mixin function copies properties from multiple sources into a destination object (rather than a single source which was the case in the Extend pattern). The source objects are passed in as the first parameter which is an array of objects.

Our destination object is an array with 4 employees. The sources are named sortable and enumerable each of which has just a single method. The mixin function takes in these sources and copies their methods into the array of employees. By the way, if the source object names sounds like interface names, then you are correct; this is by design because we are adding a sortable method and an enumeration method to the employees.

Following the mixin action we have an array that can sort its employees by age. The array also has an each method that iterates over the employees and invokes a custom callback function that displays each employee's name and age.

A possible variation of the above mixin function is deepMixin, which just like the earlier deepExtend performs deep copies of properties of all source objects provided. If you need a deepMixin in your own project then you can easily create this based on the two prior code snippets.

Functional Mixin Pattern
The Functional Mixin pattern is the logical next step for Mixin. The idea is to group related methods together in terms of functional categories. Then use these functional groups and apply these to the receiver's prototype. In this example our group is called sortable and has just one method, but others could have been added.

var Employee = function (name, gender, age) {
    this.name = name;
    this.age = age;
    this.gender = gender;
}

var Employees = function () { };
Employees.prototype = [];

var sortable = function () {
    this.sortAge = function () {
        this.sort(function (a, b) {
            return a.age - b.age;
        });
    };
    return this;
};

var enumerable = function () {
    this.each = function (callback) {
        for (var i = 0, len = this.length; i < len; i++) {
            callback(this[i]);
        }
    };
    return this;
};


sortable.call(Employees.prototype);
enumerable.call(Employees.prototype);

var employees = new Employees();

employees.push(new Employee("John", "Male", 33));
employees.push(new Employee("Peter", "Male", 45));
employees.push(new Employee("Ann", "Female", 32));
employees.push(new Employee("Tiffany", "Female", 19));

employees.sortAge();        

employees.each(function (item) {
    alert(item.name + " " + item.age);   // => Tiffany 19, Ann 32, 
                                         //    John 33, Peter 45   
});

Run

In this example there is no mixin method. Instead, we are using a call method to add a group of methods to the Employee's prototype. This will add all methods to the object's prototype. Note that the sortable and enumerable objects return this, which is important. Notice also that the employee array now derives from Array, rather than being an array instance. This was done to facilitate setting the employee array's prototype.

We've come full circle because the functional mixin pattern involves prototypal inheritance. The functional mixin is an interesting idea because it allows us to change the prototype of a constructor function just before creating a new instance. This facilitates the creation of custom objects that have a certain built-in behavior.