Skip to content

Instantly share code, notes, and snippets.

@mroderick
Forked from aron/constructors.md
Last active August 29, 2015 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mroderick/9fd7fa0b2e59252a4772 to your computer and use it in GitHub Desktop.
Save mroderick/9fd7fa0b2e59252a4772 to your computer and use it in GitHub Desktop.

Using named constructors

The general usage of a Backbone class is to use the .extend method providing an .initialize method.

var MyView = Backbone.View.extend({
  initialize: function () {
    // Setup object.
  }
});

In the background this returning a throw-away constructor object to create the new instance, and then calling .initialize to handle setup. The up-side of this, and the only reason I can see for it's existence, is that we don't have to call the parent Backbone.View method with our new instance.

The downside to this is that it removes the benefits of having a named function as the constructor. Namely debugging and introspection.

var MyView = Backbone.View.extend({});
MyView.name //=> ""
new MyView().constructor.name //=> ""
 
function MyOtherView() {
  Backbone.View.apply(this, arguments);
}
MyOtherView.name //=> "MyOtherView"
new MyOtherView().constructor.name //=> "MyOtherView"

Using the Chrome console to inspect objects is a common task, and without named constructors it can be confusing as to which type of object you are looking at.

Take the following example:

var Car = Backbone.Model.extend({initialize: function () {}});
var Bus = Backbone.Model.extend({initialize: function () {}});
var Van = Backbone.Model.extend({initialize: function () {}});
var VehicleCollection = Backbone.Collection.extend({initialize: function () {}});
var GarageView = Backbone.View.extend({initialize: function () {}});

var vehicles = new VehicleCollection();
vehicles.add(new Car());
vehicles.add(new Car());
vehicles.add(new Bus());
vehicles.add(new Van());

var garageView = new GarageView({collection: vehicles});

Backbone allows us to pass our own constructor into .extend and can be used in place of .initialize and is closer to a bare JavaScript inheritance style. This gives us much clearer output in the Chrome console.

var Car = Backbone.Model.extend({constructor: function Car() {
  Backbone.Model.apply(this, arguments);
}});
var Bus = Backbone.Model.extend({constructor: function Bus() {
  Backbone.Model.apply(this, arguments);
}});
var Van = Backbone.Model.extend({constructor: function Van(){
  Backbone.Model.apply(this, arguments);
}});
var VehicleCollection = Backbone.Collection.extend({constructor: function VehicleCollection() {
  Backbone.Collection.apply(this, arguments);
}});
var GarageView = Backbone.View.extend({constructor: function GarageView() {
  Backbone.View.apply(this, arguments);
}});

var vehicles = new VehicleCollection();
vehicles.add(new Car());
vehicles.add(new Car());
vehicles.add(new Bus());
vehicles.add(new Van());

var garageView = new GarageView({collection: vehicles});

This also allows us to provide more debugging information when passed the incorrect data. For example if we require a specific model type to be passed into a view we can use the name property to provide useful feedback to the developer.

constructor: function MyView(options) {
  Backbone.View.apply(this, arguments);

  if (!(options.model instanceof AwesomeModel)) {
    var modelName = options.model.name || "unknown";
    throw new Error("MyView expected model option to be an AwesomeModel instance but received a " + modelName + " instance");
  }
}

// Later
new MyView({model: SuperModel});
//=> error: "MyView expected model option to be an AwesomeModel instance but received a SuperModel instance"

So, I suggest that we phase out the use of .initialize and instead pass constructors. The functionality is the same, and all it requires is naming the constructor function and calling the parent constructor.

Benefits are clearer code, the inheritance pattern is visible and consistent with extending other methods, and better visual output in browser consoles that support it.

This is something that can be introduced incrementally without disrupting the existing codebase. But will improve readability as it's introduced.

@mroderick
Copy link
Author

This was originally written by my friend @aron as private gist, published with permission

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment