Backbone.js: Hacker's Guide Part 4

09 Aug 2012 | By Alex Young | Tags mvc tutorials backbone.js code-review

Last week we looked at Backbone’s History and View APIs. We’re coming to the end of this detailed look at Backbone’s internals, but there are still a few interesting things left:

  • Backbone’s inheritance implementation
  • Backbone.sync

Backbone’s inheritance Implementation

The comments indicate that the inherits function is inspired by goog.inherits. Google’s implementation is from the Closure Library, but Backbone’s API accepts two objects (incorrectly referred to as a hash) containing “instance” and “static” methods. Each of Backbone’s objects has an extend method:

Model.extend = Collection.extend = Router.extend = View.extend = extend;

Most development with Backbone is based around inheriting from these objects, and they’re designed to mimic a classical object-oriented implementation.

Backbone uses Underscore’s extend method:

each(slice.call(arguments, 1), function(source) {
  for (var prop in source) {
    obj[prop] = source[prop];
  }
});
return obj;

This isn’t the same as ES5’s Object.create, it’s actually copying properties (methods and values) from one object to another. Since this isn’t enough to support Backbone’s inheritance and class model, the following steps are performed:

  1. The instance methods are checked to see if there’s a constructor property. If so, the class’s constructor is used, otherwise the parent’s constructor is used (i.e., Backbone.Model)
  2. Underscore’s extend method is called to add the parent class’s methods to the new child class
  3. The prototype property of a blank constructor function is assigned with the parent’s prototype, and a new instance of this is set to the child’s prototype property
  4. Underscore’s extend method is called twice to add the static and instance methods to the child class
  5. The child’s prototype’s constructor and a __super__ property are assigned

This pattern is also used for classes in CoffeeScript, so Backbone classes are compatible with CoffeeScript classes.

Update: Jeremy Ashkenas clarified this process on Twitter:

… it’s just your basic prototype chain, plus one extra goodie: any constructor properties (static) are copied over as well.

Backbone’s Sync API

The Backbone.sync method is intended to be overridden to support other backends. The built-in method is tailed to a certain breed of RESTful JSON APIs – Backbone was originally extracted from a Ruby on Rails application, which uses HTTP methods like PUT the same way.

The way this works is the model and collection classes have a sync method that calls Backbone.sync. Both will call this.sync internally when fetching, saving, or deleting items.

The sync method is called with three parameters:

  • method: One of create, update, delete, read
  • model: The Backbone model object
  • options: May include success and error methods

Implementing a new sync method can use the following pattern:

Backbone.sync = function(method, model, options) {
  var requestContent = {}, success, error;

  function success(result) {
    // Handle results from MyAPI
    if (options.success) {
      options.success(result);
    }
  }

  function error(result) {
    // Handle results from MyAPI
    if (options.error) {
      options.error(result);
    }
  }

  options || (options = {});

  switch (method) {
    case 'create':
      requestContent['resource'] = model.toJSON();
      return MyAPI.create(model, success, error);

    case 'update':
      requestContent['resource'] = model.toJSON();
      return MyAPI.update(model, success, error);

    case 'delete':
      return MyAPI.destroy(model, success, error);

    case 'read':
      if (model.attributes[model.idAttribute]) {
        return MyAPI.find(model, success, error);
      } else {
        return MyAPI.findAll(model, success, error);
      }
  }
};

This pattern delegates API calls to a new object, which could be a Backbone-style class that supports events. This can be safely tested separately, and potentially used with libraries other than Backbone.

There are quite a few sync implementations out there:


blog comments powered by Disqus