Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Backbone Part 2

  • Loading branch information...
commit ba81592d26bf6416e53969a61b5ab5542d03bf28 1 parent 265c159
Alex Young authored July 26, 2012
75  _posts/2012-07-26-mvstar-3.md
Source Rendered
... ...
@@ -0,0 +1,75 @@
  1
+---
  2
+layout: post
  3
+title: "Backbone.js: Hacker's Guide Part 2"
  4
+author: Alex Young
  5
+categories: 
  6
+- mvc
  7
+- tutorials
  8
+- backbone.js
  9
+- code-review
  10
+---
  11
+
  12
+[Last week](/2012/07/19/mvstar-2/) we looked at Backbone.js's internals, covering configuration, server support, events, and models.  I actually really enjoy looking at projects this way, it's one of the best ways to learn new programming techniques.  So let's continue dissecting Backbone by taking a look at `Backbone.Collection`.
  13
+
  14
+###Constructor
  15
+
  16
+[Backbone.Collection](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L549) is a constructor function that accepts an array of models and an options object.
  17
+
  18
+As an aside, notice that [void 0](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L558) is used in this code.  To understand why, recall that [the void operator](https://developer.mozilla.org/en/JavaScript/Reference/Operators/void) returns `undefined`.  Since ECMAScript 5, the `undefined` property isn't writable, so it's safe to use it.  However, in earlier versions it was writable, which meant malicious code could technically take advantage of this fact by assigning a value to the `undefined` property of the _global object_.  The `void` operator expects an expression, so `void 0` is considered the idiomatic way of safely obtaining `undefined`.
  19
+
  20
+The constructor calls the [reset](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L558) method, which removes existing models and adds new ones.  This is similar to instantiating a collection with no models, and then manually calling `add` on each one.
  21
+
  22
+###Inheritance and Mixins
  23
+
  24
+The [Collection class inherits from Backbone.Events](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L565).  Events are used both publicly and internally.  There's a [toJSON](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L577) method that iterates over each model and calls the model's `toJSON` method.  This brings up an interesting point: collections use methods from Underscore.js, but `Collection` doesn't inherit from Underscore.  Why not?  Well, [certain methods are manually assigned to Collection.prototype](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L863-875), while others are rewritten in ways that make sense in Backbone.  For example, the [pluck](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L748) method works on model attributes, and [sort](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L734) uses the `boundComparator` which has a slightly different API to `Array.prototype.sort`.
  25
+
  26
+###Adding and Removing Items
  27
+
  28
+Collections are basically an array of models with events, wrapped with convenient Underscore-like iterator methods.  The `add` method is always called however models are added, which means it's a good place to do housekeeping like [preventing invalid models and duplicates](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L595-612) from being inserted into the collection.  Models are also [indexed by id](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L616-620), and all model events are bound to [\_onModelEvent](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L851).  This method dynamically adds new models, removes deleted ones, and updates models with changes.
  29
+
  30
+If the collection requires sorting, the `add` method will [call sort](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L636) once all models have been processed.  And, if the `silent` option isn't set, an `add` event will be triggered for each model that was successfully added.
  31
+
  32
+It naturally follows that the [remove](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L650) method has a fair amount of work to do, given the complexity of `add`.  The indexed ids must be deleted, and [\_removeReference](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L842) is called to remove the model's reference back to the collection.
  33
+
  34
+Deleting items in JavaScript is interesting, because we actually have the `delete` keyword to do this for us.  However, `delete` is only used for properties, so the authors have used the `Array.prototype.splice` technique to delete models from the array.  The `add` and `remove` methods also update the `length` property, which allows the collection to behave in an Array-like manner, and helps support the mixed-in Underscore methods.
  35
+
  36
+Now take a look at the simplicity of the [where](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L721) method.  It basically loops over each model, comparing an attributes object.  This is simple because the `filter` method is taken directly from Underscore.
  37
+
  38
+###Chainable API
  39
+
  40
+Another bit of sugar is the support for Underscore's [chain](https://github.com/documentcloud/backbone/blob/ddefd21167c27d98fd1eb05a44e330a2313055f6/backbone.js#L816) method.  This works by calling the original method with the current array of models and returning the result.   In case you haven't seen it before, the chainable API looks like this:
  41
+
  42
+{% highlight javascript %}
  43
+var collection = new Backbone.Collection([
  44
+  { name: 'Tim', age: 5 },
  45
+  { name: 'Ida', age: 26 },
  46
+  { name: 'Rob', age: 55 }
  47
+]);
  48
+
  49
+collection.chain()
  50
+  .filter(function(item) { return item.get('age') > 10; })
  51
+  .map(function(item) { return item.get('name'); })
  52
+  .value();
  53
+
  54
+// Will return ['Ida', 'Rob']
  55
+{% endhighlight %}
  56
+
  57
+Some of the Backbone-specific method will return `this`, which means they can be chained as well:
  58
+
  59
+{% highlight javascript %}
  60
+var collection = new Backbone.Collection();
  61
+
  62
+collection
  63
+    .add({ name: 'John', age: 23 })
  64
+    .add({ name: 'Harry', age: 33 })
  65
+    .add({ name: 'Steve', age: 41 });
  66
+
  67
+collection.pluck('name');
  68
+// ['John', 'Harry', 'Steve']
  69
+{% endhighlight %}
  70
+
  71
+###Conclusion
  72
+
  73
+I've been using Backbone for a while, and I've never really thought about how the `Backbone.Collection` methods can be chained.  Sometimes it's difficult to tell what's possible though -- once you're in an Underscore chain you can't use methods like `pluck` because Backbone's models use the `get` method to access attributes, so you'll end up with an array of `undefined` values.
  74
+
  75
+Next week I'll continue looking at Backbone by investing the formidable routing and history APIs.
6  js101.html
@@ -15,11 +15,11 @@
15 15
   </ul>
16 16
   <h2>Classes and Inheritance</h2>
17 17
   <ul>
18  
-    <li><a href="http://dailyjs.com/2012/05/21/js101-prototype">The `prototype` Property</a></li>
  18
+    <li><a href="http://dailyjs.com/2012/05/21/js101-prototype">The <code>prototype</code> Property</a></li>
19 19
     <li><a href="http://dailyjs.com/2012/05/28/js101-prototype-chains">Inheritance Chains</a></li>
20  
-    <li><a href="http://dailyjs.com/2012/06/04/js101-object-create">Extending Objects with `Object.create`</a></li>
  20
+    <li><a href="http://dailyjs.com/2012/06/04/js101-object-create">Extending Objects with <code>Object.create</code></a></li>
21 21
     <li><a href="http://dailyjs.com/2012/06/11/js101-constructor-functions">Constructor Functions</a></li>
22  
-    <li><a href="http://dailyjs.com/2012/06/18/js101-this">Working with `this`</a></li>
  22
+    <li><a href="http://dailyjs.com/2012/06/18/js101-this">Working with <code>this</code></a></li>
23 23
     <li><a href="http://dailyjs.com/2012/06/25/this-binding">Call, Apply, and Bind</a></li>
24 24
   </ul>
25 25
   <h2>Functions</h2>
16  tags.html
@@ -561,6 +561,10 @@ <h3 id=".net">.net</h3>
561 561
             <div>19 Jul 2012</div>
562 562
             <a href="/2012/07/19/mvstar-2">Backbone.js: Hacker's Guide</a>
563 563
           </li>
  564
+          <li>
  565
+            <div>26 Jul 2012</div>
  566
+            <a href="/2012/07/26/mvstar-3">Backbone.js: Hacker's Guide Part 2</a>
  567
+          </li>
564 568
 </ul>      <h3 id="banking">banking</h3>
565 569
 <ul class="posts">          <li>
566 570
             <div>01 Feb 2012</div>
@@ -976,6 +980,10 @@ <h3 id=".net">.net</h3>
976 980
             <div>19 Jul 2012</div>
977 981
             <a href="/2012/07/19/mvstar-2">Backbone.js: Hacker's Guide</a>
978 982
           </li>
  983
+          <li>
  984
+            <div>26 Jul 2012</div>
  985
+            <a href="/2012/07/26/mvstar-3">Backbone.js: Hacker's Guide Part 2</a>
  986
+          </li>
979 987
 </ul>      <h3 id="codereview">codereview</h3>
980 988
 <ul class="posts">          <li>
981 989
             <div>19 Mar 2010</div>
@@ -6358,6 +6366,10 @@ <h3 id=".net">.net</h3>
6358 6366
             <div>19 Jul 2012</div>
6359 6367
             <a href="/2012/07/19/mvstar-2">Backbone.js: Hacker's Guide</a>
6360 6368
           </li>
  6369
+          <li>
  6370
+            <div>26 Jul 2012</div>
  6371
+            <a href="/2012/07/26/mvstar-3">Backbone.js: Hacker's Guide Part 2</a>
  6372
+          </li>
6361 6373
 </ul>      <h3 id="narwhal">narwhal</h3>
6362 6374
 <ul class="posts">          <li>
6363 6375
             <div>08 Mar 2010</div>
@@ -10066,6 +10078,10 @@ <h3 id=".net">.net</h3>
10066 10078
             <div>23 Jul 2012</div>
10067 10079
             <a href="/2012/07/23/js101-scope">JS101: A Brief Lesson on Scope</a>
10068 10080
           </li>
  10081
+          <li>
  10082
+            <div>26 Jul 2012</div>
  10083
+            <a href="/2012/07/26/mvstar-3">Backbone.js: Hacker's Guide Part 2</a>
  10084
+          </li>
10069 10085
 </ul>      <h3 id="twitter">twitter</h3>
10070 10086
 <ul class="posts">          <li>
10071 10087
             <div>22 Jun 2010</div>

0 notes on commit ba81592

Please sign in to comment.
Something went wrong with that request. Please try again.