Backbone.js is interesting because it gives you the basic framework of an MVC application without enforcing patterns on you. However, in larger web application it's always important to ensure your structure promotes code reuse and good organization for future development. One such way is through inheritance of views, and in this post I will describe how to create an inheritance chain using Backbone Views.
Backbone views provide a basic implementation to represent a view, but there are also areas where further functionality could be required, such as an improved handling of view disposal, or just general application logic you feel a subset of your views should have.
In our application, we want to be able to create subclasses of
Backbone.View for disposable views, drop down views, table views, row views, cell views and so on, whilst maintaining the ability to inherit further in the future. Inheriting from
Backbone.View isn't as easy as it seems, especially when you consider that you would like children to inherit events and attributes of the parent, whilst also specifying their own. To this end, I set about creating an extensible inheritance chain between my views that would suit my development needs now and in the future.
For our first example, let's assume we want to define a
BaseView from which our other views will inherit from. This view will contain the logic surrounding inheriting events and attributes. You might expect to inherit from
Backbone.View like so:
However, this solution can cause several issues. Let's delve a little deeper into this.
Prototype Properties vs. Instance Variables
When you use extend on
Backbone.View and specify properties, they aren't specific to every instance of
BaseView you create. They're properties on the prototype of
Backbone.View, not variables on the instance of your
BaseView. Consider the following:
As shown, the modification of
ChildTwo has affected
ChildOne's event object, even though they should be completely separate extensions.
Extend works by extending the
Backbone.View.prototype with the object literal you specify. When we edit the events object in
ChildTwo, we're actually editing the prototype of
BaseView, rather than the instance of
ChildOne will also have the same modifications because it uses the prototype of
There are actually two underlying problems here. Firstly, we want instance variables rather than prototype properties, so that every instance of our
ChildViews get their own events object. Secondly, we don't want to have to declare a new events object every time, as the parent may have events we want to keep and we don't want to duplicate code across children. So, let's solve them:
Backbone Inheritance with Instance Variables
We need to adjust the way we inherit from
Backbone.View. Firstly, we define our
BaseView as a function, which will serve as our constructor. In this constructor, we can then define the instance variables we want every instance of our
BaseView to have.
We then extend the prototype to copy over all the prototype properties from
Backbone.View, and assign the extend to our extend.
This is pretty simple, we're calling
Backbone.View in our constructor, and then extending the
Backbone.View prototype. This gives us the opportunity to define the instance variables in the constructor of
Inherit values from a parent's prototype property
attribute properties are on the prototype of
Backbone.View. However, we don't want to overwrite the objects in every child class, and would rather have the events concatenated with the events of the parent. This requires some changes to our
Let's look at what we're doing here. Firstly, we define the instance variable
inheritedEvents, which is an array of event objects. When a child wants to add an object of arrays to be handled, it calls
this.addEvents(eventObj) to have it added to the array. Because this is an instance variable, the events are individual to each instance and we don't need to override the parent's object.
We've also defined a prototype property called
baseEvents, which is where you would put any events common across all
Finally, we've changed
events to be a function which returns the concatenation of the base events and all inherited events.
A child could add its own events like so:
and it would still have the events defined in
Subclassing Children - the full chain
Once we have this step handled, we can apply it throughout a chain of children. As long as each potential parent inherits from its parent in the correct way, introducing new children is seamless provided you do not override the
events function with an object literal, and call
addEvents to add your events.
The attributes object is handled differently. Unlike events, it cannot be a function, but it is used in Backbone's
make function to create the element. For this reason, we need to keep the attributes object an object literal and also up-to-date as children add attributes to it. One solution is to make attributes an instance variable, and have it kept up-to-date with
addAttributes like so:
I'm concerned at the processing overhead of this (though I can't see there being much of an issue, as typically you'd add attributes when you initialize a view, before the element is in the DOM) of this, however, and would like to do some more investigation and I am open to ideas as to how to improve it.
Inheritance of Functions
Things like functions which are defined on the prototype are still overriden by children, which may not be desirable. A common pattern would be something like:
In this case, you'd have your children override
initializeInternal. However, as your inheritance chain gets deeper, you may want to perform step-by-step initialization as you get further down the chain, and overriding
initializeInternal would cause a lot of duplicate code at each childless view. A solution such as creating an initialize chain may work here, and having the root view have a chain of functions to call on initialize. Something like:
This code is untested, and I'm not sure where and how you would define your initialization functions without completely changing the pattern of creating views. Currently, we keep our functional logic as low down the inheritance chain as possible to avoid a lot of overriding.
By inheriting from
Backbone.View you improve the readability (i.e. views are less cluttered), promote code reuse and make future developments easy. Although how to inherit from views isn't obvious at first, and Backbone's way of handling events and attributes make things a little tricky, I think being able to perform classical inheritance with Backbone is an incredibly important concept for large-scale web applications.