Taking a quick look at the backbone.js source code

Delving into backbone.js source code
http://documentcloud.github.com/backbone/backbone.js

Today I decided to take a quick look at the backbone.js source at see what was going on behind the scenes of this awesome MVC framework.

Review was done on previous version of Backbone.js 0.5.3 (latest version is Backbone.js 0.9.1)

<h2>line 32: require('underscore')._;</h2>

// Require Underscore, if we're on the server, and it's not already present.
var _ = root._;
if (!_ &amp;&amp; (typeof require !== 'undefined')) _ = require('underscore')._;
  • Firstly, root references the Global JavaScript Object.
  • Require is used for loading top level JavaScript files or inside modules for dynamically fetching dependencies.
  • Further reading on JavaScript Global objects: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects
  • It seems backbone.js can be used with non-browser JavaScript backend languages that follow the CommonJS spec like Node.js.
  • CommonJS is a server side JavaSCript framework. It’s checking for the presence of require from the CommonJS module specification. It’s saying that if the global object doesn’t contain _, try to require the underscore module (if require is defined) and get _ from there.
  • Further reading on require() in node.js docs: http://nodejs.org/docs/v0.4.2/api/modules.html#loading_from_the_require.paths_Folders
    In CommonJS, Underscore may now be required with just: var _ = require(“underscore”).
  • Now we have a whole list of functions available to us all starting with the underscore variable name (eg _.size(), _.toArray() etc…)

line 35: $ = root.jQuery

// For Backbone's purposes, jQuery or Zepto owns the `$` variable.
var $ = root.jQuery || root.Zepto;

Zepto.js is very much like a stripped down version of jQuery except it has slightly different function names such as ajaxJSONP() and a few others. Being only 10kb mninfied it’s primary focus is on mobile development and this can be seen in the source code.

['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'longTap'].forEach(function(m){
  $.fn[m] = function(callback){ return this.bind(m, callback) }
});

Line 132: Backbone.Model

// Backbone.Model
// --------------

// Create a new model, with defined attributes. A client id (`cid`)
// is automatically generated and assigned for you.
Backbone.Model = function(attributes, options) {
  var defaults;
  attributes || (attributes = {});
  if (defaults = this.defaults) {
    if (_.isFunction(defaults)) defaults = defaults.call(this);
    attributes = _.extend({}, defaults, attributes);
  }
  this.attributes = {};
  this._escapedAttributes = {};
  this.cid = _.uniqueId('c');
  this.set(attributes, {silent : true});
  this._changed = false;
  this._previousAttributes = _.clone(this.attributes);
  if (options &amp;&amp; options.collection) this.collection = options.collection;
  this.initialize(attributes, options);
};

This is the core model prototype object where all the attributes are set for the model.

this.cid = _.uniqueId('c');

Here it’s also generating a unique id for the cid property using the _.uniqueId() function which takes the prefix as a paramter, in this case a c so would return say c104, c201 etc…

And to set the defaults for a model you could do the following:

var Meal = Backbone.Model.extend({
  defaults: {
    "appetizer":  "caesar salad",
    "entree":     "ravioli",
    "dessert":    "cheesecake"
  }
});

alert("Dessert will be " + (new Meal).get('dessert'));

Line 150: _.extend(Backbone.Model.prototype

_.extend(Backbone.Model.prototype, Backbone.Events, {
    ...
    methods: initialize(), escape(), set(), get() etc...
    ...

This is simply adding the methods and event object into the model prototype object so it has all the functionality using the extend() function (provided by underscore.js).

Line 414: Backbone.Collection

// Backbone.Collection
// -------------------

// Provides a standard collection class for our sets of models, ordered
// or unordered. If a `comparator` is specified, the Collection will maintain
// its models in sort order, as they're added and removed.
Backbone.Collection = function(models, options) {
  options || (options = {});
  if (options.comparator) this.comparator = options.comparator;
  _.bindAll(this, '_onModelEvent', '_removeReference');
  this._reset();
  if (models) this.reset(models, {silent: true});
  this.initialize.apply(this, arguments);
};

Line 656: Backbone.Router

// Backbone.Router
// -------------------

// Routers map faux-URLs to actions, and fire events when routes are
// matched. Creating a new one sets its `routes` hash, if not set statically.
Backbone.Router = function(options) {
  options || (options = {});
  if (options.routes) this.routes = options.routes;
  this._bindRoutes();
  this.initialize.apply(this, arguments);
};

Line 735: Backbone.History

// Backbone.History
// ----------------

// Handles cross-browser history management, based on URL fragments. If the
// browser does not support `onhashchange`, falls back to polling.
Backbone.History = function() {
  this.handlers = [];
  _.bindAll(this, 'checkUrl');
};

Line 879: Backbone.View

// Backbone.View
// -------------

// Creating a Backbone.View creates its initial element outside of the DOM,
// if an existing element is not provided...
Backbone.View = function(options) {
  this.cid = _.uniqueId('view');
  this._configure(options || {});
  this._ensureElement();
  this.delegateEvents();
  this.initialize.apply(this, arguments);
};

Line 1038: Backbone.sync

// Backbone.sync
// -------------

// Override this function to change the manner in which Backbone persists
// models to the server. You will be passed the type of request, and the
// model in question. By default, uses makes a RESTful Ajax request
// to the model's `url()`. Some possible customizations could be:
//
// * Use `setTimeout` to batch rapid-fire updates into a single request.
// * Send up the models as XML instead of JSON.
// * Persist models via WebSockets instead of Ajax.
//
// Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
// as `POST`, with a `_method` parameter containing the true HTTP method,
// as well as all requests with the body as `application/x-www-form-urlencoded` instead of
// `application/json` with the model in a param named `model`.
// Useful when interfacing with server-side languages like **PHP** that make
// it difficult to read the body of `PUT` requests.
Backbone.sync = function(method, model, options) {
  var type = methodMap[method];

Line 1137: throw new Error(

// Throw an error when a URL is needed, and none is supplied.
var urlError = function() {
  throw new Error('A "url" property or function must be specified');
};

This is a helper function which throws a new custom JavaScript error. Just like this but will a custom message.

try{
  document.body.filters[0].apply()
}
catch(e){
  alert(e.name + "\n" + e.message)
}

Line 1153: var escapeHTML = function(string)

// Helper function to escape a string for HTML rendering.
var escapeHTML = function(string) {
  return string.replace(/&amp;(?!\w+;|#\d+;|#x[\da-f]+;)/gi, '&amp;amp;').replace(/</g, '&amp;lt;').replace(/>/g, '&amp;gt;').replace(/"/g, '&amp;quot;').replace(/'/g, '&amp;#x27;').replace(/\//g,'&amp;#x2F;');
};

Helper function to escapeHTML which uses regex replaces.

This was just a quick at backbone.js i’m sure some of you have looked a lot closer and would like to know your thoughts. Leave a comment.