A Better way of extending Backbone Models and Views
Although Backbone has some level of object inheritance support, it's only meant to extend it's own Classes and nothing more. When you want to use an already existing Model or View as a base for your new extended Objects, the default extend method usually falls out short.
For example, you have no way of using the methods of Parent class on your Child class and if you want to extend an already existing Model's defaults or View's events you'll have to either call them via prototype
and extend them or re-write them for your Child class again.
In order to solve these issues, I put together a quick new method for Views and Models. It automatically extends defaults
and events
attributes for you and defines a _super
property which you can safely reference to your Parent class and use it's methods while overwriting them.
Here is the code:
(function(Model){
'use strict';
// Additional extension layer for Models
Model.fullExtend = function (protoProps, staticProps) {
// Call default extend method
var extended = Model.extend.call(this, protoProps, staticProps);
// Add a usable super method for better inheritance
extended.prototype._super = this.prototype;
// Apply new or different defaults on top of the original
if (protoProps.defaults) {
for (var k in this.prototype.defaults) {
if (!extended.prototype.defaults[k]) {
extended.prototype.defaults[k] = this.prototype.defaults[k];
}
}
}
return extended;
};
})(Backbone.Model);
(function(View){
'use strict';
// Additional extension layer for Views
View.fullExtend = function (protoProps, staticProps) {
// Call default extend method
var extended = View.extend.call(this, protoProps, staticProps);
// Add a usable super method for better inheritance
extended.prototype._super = this.prototype;
// Apply new or different events on top of the original
if (protoProps.events) {
for (var k in this.prototype.events) {
if (!extended.prototype.events[k]) {
extended.prototype.events[k] = this.prototype.events[k];
}
}
}
return extended;
};
})(Backbone.View);
And here is an example of how to use it with Models, same applies for Views too
var Car = Backbone.Model.extend({
defaults:{
engine: 'gasoline',
hp: 0,
doors: 4,
color: 'generic'
},
engine: function(){
return 'Wroomm';
}
});
// Ferrari will have all attributes from Car Model
// But will also have it's own modifications
var Ferrari = Car.fullExtend({
defaults: {
hp: 500,
color: 'red',
doors: 2
},
// Engine method can use the engine method on Car too
engine: function(){
var ret = this._super.engine();
return ret + '!!!!';
}
});
Hope it's useful for you.
Written by Serkan Yerşen
Related protips
8 Responses
Nice! I never really noticed it since I use CoffeeScript to extend Backbone classes... http://coffeescript.org/#classes
Yes, Backbone has built-in support for CoffeeScript and sometimes I think CoffeeScript was invented to write easier Backbone code :) It's just so convenient
Nice add on! :-) This really helps.
The ferrari engine() method doesn't seem to work am I using this wrong?
test = new Ferrari()
child {cid: "c4", attributes: Object, _changing: false, _previousAttributes: Object, changed: Object…}
test.engine()
TypeError: Cannot read property 'engine' of undefined
I think that the line:
extended._super = this.prototype;
should be
extended.prototype._super = this.prototype;
You’re a life saver. I made an AMD-ready version. Thanks.
Thanks @tomlue, I've updated the example now.
no problem, thanks for the code. I am curious, when you create an instance of an extending class how do you make the super class initialize function fire?
Right now I just write this._super.initialize.call(this,args) in the extending classes initialize, but it would be nice if this happened implicitly.