Skip to content

Instantly share code, notes, and snippets.

@rishabhp
Last active Aug 29, 2015
Embed
What would you like to do?
Mixins in JavaScript

Reference: https://javascriptweblog.wordpress.com/2011/05/31/a-fresh-look-at-javascript-mixins/

Simply put, in JavaScript, implementation of mixins can be done via copying or cloning attributes and methods from mixin objects (reusable code) to Constructor prototypes (main classes).

Classic Mixins (from Reference)

This is like the first approach to come to mind.

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

// Helper to mixin (by extending/augmenting)
function extend(destination, source) {
  for (var k in source) {
    if (source.hasOwnProperty(k)) {
      destination[k] = source[k];
    }
  }
  return destination; 
}

var RoundButton = function(radius, label) {
  this.radius = radius;
  this.label = label;
};
 
extend(RoundButton.prototype, circleFns);
extend(RoundButton.prototype, buttonFns); // not defined but more ...

In underscore, _.extend can be used:

_.extend(RoundButton.prototype, circleFns);

Functional Mixins (from Reference)

The reference's author believes that mixins should be a process, not an object. It should be a verb, not a noun. So here's a new approach:

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

IMHO, this is much cleaner (and lighter) :-). Some caching magic can also be 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'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment