Classes, Inheritance And Mixins In JavaScript
JavaScript doesn’t have native support for classes. Functions can be used to simulate classes (somewhat), but in general JavaScript is a class-less language. Everything is an object. This makes inheritance particularly strange, since objects inherit from objects, not classes from classes as in languages like Ruby or Java.
CoffeeScript does have support for classes though - that is to say, class
is a keyword. So how does that work, if JavaScript doesn’t have classes? (CoffeeScript just compiles down to JavaScript, so it’s not a superset of the language - it merely adds some syntactical sugar)
Classes in CoffeeScript and JavaScript
This CoffeeScript ‘class’
is equivalent to this JavaScript:
This is one pattern for defining classes in JavaScript - creating a named function and adding methods to the prototype of the function. (The other two common patterns are using an object literal and declaring a singleton function)
When defining a class with this pattern (either in CoffeeScript or JavaScript) the function actually behaves very similar to classes in other languages.
(The JavaScript for this code looks exactly the same, just add some semicolons!)
CoffeeScript also allows us to have inheritance between classes. So how does that work, if we just said that JavaScript doesn’t really have classes (just functions) and that objects inherit from objects, not classes from classes?
Class Inheritance in CoffeeScript and JavaScript
Let’s add some inheritance to our CoffeeScript ‘class’.
Here is the equivalent JavaScript (I have reformatted the output from the CoffeeScript compiler to make it a bit more readable).
That is some pretty intense JavaScript, but the magic is happening in the extend
function. There are 2 types of methods that need to be inherited from the parent - methods defined on the parent itself (we can think of these as class methods) and methods defined on the prototype of the parent (we can think of these as instance methods).
The first thing that happens is that all the class methods on the parent are added to the child (note - not to the prototype of the child). This concept is pretty simple - since functions in JavaScript are objects, we can effectively loop through all the functions of the parent class (function) and add them to the child class (function).
A special constructor function (called ctor
) is then created to act as the prototype of the child class. CoffeeScript does a lot of work here just to enable us to call super
when we override parent methods in the child. (super
is treated as a keyword and CoffeeScript does some additional magic in order to make it all work)
As I mentioned earlier, in JavaScript objects inherit from objects (instead of classes from classes). We can therefore set the prototype for the child class (function) to an instance of the ctor
function - because they’re both just objects. Any new instances of the child class will also have the same prototype and because the ctor
function has the parent class as a prototype we are effectively using normal prototypal inheritance with an additional level of indirection - all to enable calls to super
(which is actually really useful).
So if CoffeeScript (and as a result, JavaScript) can fake classes with functions and inheritance with functions, could it fake mixins?
Mixins in CoffeeScript and JavaScript
In order to implement mixins in CoffeeScript (or JavaScript), we would effectively need to copy the functions from one class (function) into another. As we have seen with the extend
function that CoffeeScript uses for inheritance, copying functions between classes is actually rather easy.
I’m referring to the first part of the extend
function:
Let’s look at how we might implement mixins in CoffeeScript:
Within the Employee class (function) I am simply looping through all the properties on the Manager class (function) and assigning them to the prototype of the Employee class.
This might seem strange until you consider that this is exactly how we have been declaring methods on classes all along!
In this example the age
method compiles down to this JavaScript:
This is equivalent to how I am assigning the mixin methods - this piece of CoffeeScript:
Is again equivalent to the same JavaScript:
So this pattern really allows us to assign methods to our ‘class’ in exactly the same way as we did before. The only difference is that our Manager ‘class’ (in Ruby we would call this a module) assigns functions directly to the Manager ‘class’, instead of to the propotype. This makes perfect sense, since we don’t necessarily want to have to create an instance of the Manager ‘class’ in order to use it as a mixin in the Employee ‘class’.
There is a very strong similarity to how mixins behave in Ruby, except this is actually a bit cleaner. In Ruby a mixin is actually injected in the inheritance chain, where in JavaScript the function is directly assigned to the class.
Why do we need Mixins?
I started playing around with mixins in CoffeeScript because I became frustrated with sharing code via inheritance. When the only way to share code between classes is inheritance, you can easily end up with inheritance where it doesn’t really make sense. (When all you have is a hammer, everything looks like a nail!)
This pattern would at the very least provide an alternative to inheritance - which is clearly not always the best solution. You can find all the code on Plunker. Happy coding.