Last Updated: February 25, 2016
·
25.09K
· serkanyersen

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.

8 Responses
Add your response

Nice! I never really noticed it since I use CoffeeScript to extend Backbone classes... http://coffeescript.org/#classes

over 1 year ago ·

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

over 1 year ago ·

Nice add on! :-) This really helps.

over 1 year ago ·

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

over 1 year ago ·

I think that the line:

extended._super = this.prototype;

should be

extended.prototype._super = this.prototype;

over 1 year ago ·

You’re a life saver. I made an AMD-ready version. Thanks.

over 1 year ago ·

Thanks @tomlue, I've updated the example now.

over 1 year ago ·

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.

over 1 year ago ·