Backbone.js
supply structure to web applications
自己紹介
● 清水 大輔(しみず だいすけ)
● NHN Japan
  LINEのJS書いてます
● 著書『iPhone & Android HTML5ではじめるアプ
  リ制作の手引き 』
● 趣味:フットサル、ジョギング
● twitter id @tori3_jp
backbone.jsとは
● 開発者はJeremy Ashkenas氏
  CoffeeScript, underscore.js

● JavaScript MVC Framework
  Events, Model, Collection, View, Route

● Document

● 採用事例
  LinkedIn, foursquare, pandora, etc...
他にも
● Knockout.js (MVVM)

● Javascript MVC

● Ember.js

● Spine.js

● Angular.js
MVCとは
"Model View Controller(モデル・ビュー・コントローラ; MVC)
は、コンピュータ内部のデータをユーザに提示し、それに対して
ユーザが何らかの指示を出すタイプの、独自のユーザーインタ
フェースをもつアプリケーションソフトウェアを、以下に述べるよ
うなmodel・view・controllerの3つの部分に分割して設計・実装
するという技法、又はそのような構造をいう。
各モジュールが比較的截然と分かれ、プログラムの見通しがよ
くなるとともに、ユーザインタフェース (UI) 部分を別のモジュー
ルに取り替えることが容易となるのが利点である。自動プログラ
ミングなどにも適している。"
                         出典:wikipedia
・HTML5、ブラウザの高速化などに伴って
   Webアプリでよりネイティブアプリ近いUXが可能に

  => JavaScriptで複数のViewを切り替えるようなアプリ
 => 保守性、品質を保つには高いスキルやコストが必要
  => OOPのデザインパターンの利用
  => JavaScript MVC Framework
注意

● なんでもかんでもMVCが必要というわけではない
 etc: 単純なTab UIの実装、ちょっとしたeffect処理

● backbone.jsを使った = MVCではない

● MVC is dead なんて話題になりましたが...
 プレゼンテーションとドメインの分離が重要
Backbone.jsでのMVC
MVCだが....
Backbone.Model => Model
Backbone.Collection => Group化したModel
Backbone.Router => Controllerの一部とURLとのMapping
Backbone.View => ViewとController (Modelを内包)
Template => View
Dependency
● jQuery or Zepto

● Underscore.js

● ( json2.js)
Events
Backbone.View, Mdoel, Collectionは
全てこのBackbone.Eventsを継承

on(), off(), trigger()のメソッドを実装

=> Observe Pattern
Model
====================================
var model = Backbone.Model.extend({
    update: function(value) {
        ・・・
        // "change" eventをtirgger
        this.trigger("change");
      }
});

View
====================================
var view = Backbone.View.extend({
    initialize: function() {
          // modelのeventにattach
          this.model.on("change", this.onChange, this);
    },
    onChange: function(arg) {
          ・・・
    }
});
Model
ドメイン(ビジネスロジック)の実装
データ同期に透過的なRESTFul APIを提供
(Backbone.Sync)

save() => POST or PUT
destroy() => DELETE
fetch() => GET
var Book= Backbone.Model.extend({
    // リソースURL
      url: function() {
           return "http://hoge/api" + ((this.id) ? "/" + this.id : "");
      },

      // デフォルトプロパティを設定
      defaults: {
          title: "",
          author: "",
          isbn: "",
          price: 0
      }

      // コンストラクタ
      initialize: function() {
           ・・・
      }
});
var book = new Book({
     title : "JavaScript MVC",
     author: "hoge hoge",
     price : 3000
});

// POST
book.save();

=> POST : http://hoge/api

// PUT ( idに1111が設定されているとする)
book.set({price : 1000});
book.save();
=> PUT : http://hoge.hoge/api/1111

//DELETE
book.destroy()
=> DELETE : http://hogehoge/api/1111
メソッドのオーバーライド。スーパークラスのメソッド呼び出し

var book = new Backbone.Model({
    set : function(obj) {
         obj.price = obj.price * 0.05;
         Backbone.Model.prototype.set.call(this, obj);
    }
});
Backbone.Syncをオーバーライドすることで、他のリソース(localStorageなど)を使えま
す

Backbone.sync = function(method, model, options) {

 var resp;
 var store = model.localStorage || model.collection.localStorage;

 switch (method) {
   case "read": resp = model.id ? store.find(model) : store.findAll(); break;
   case "create": resp = store.create(model);                  break;
   case "update": resp = store.update(model);                    break;
   case "delete": resp = store.destroy(model);                  break;
 }
Collection
ModelをGroup(LIST)化したもの

underscore.jsのメソッドに大部分が依存
● each
● sort
● shuffle
● reset
● filter
var BookCollection = new Backbone.Collection.extend({

      // collectionするmodel
      model: Book,

      // コンストラクタ
      initialize: function() {
      },

      // comparator
      comparator: function(book) {
           return book.get("price");
      }
});
var bookList = new BookCollection([
    {title : "aaaa", author: "hoge1", price: 1000},
    {title : "bbb", author: "hoge2", price: 2000},
    {title : "ccccc", author: "hoge3", price: 3000}
]);

// push
bookList.push(new Book({title : "dddd", author: "hoge4", price: 600});

// pop
var book1 = bookList.pop();

// sort ( price 昇順にソート)
bookList.sort();

// indexを指定して取得
var book2 = bookList.at(1);
View
プレゼンテーション部分の実装
● templateを使ったDOM作成
● DOM操作
● delegateでのDOM Event処理
● model (collection)のcontrol
var BookView = Backbone.View.extend({

    tagName: "li",

    // delegate event
    events: {
         "click .removeBtn" : "onRemove"
    },

    // テンプレート
    tmpl : $("#bookTmpl"),

    // コンストラクタ
    initialize: function() {
          this.model.bind("destory", this.change, this);
    },

    // レンダリング
    render : function() {
        this.$el.html(_.tmplate(this.tmpl.text(), this.model.toJSON());
        return this.$el;
    },
// 削除ボタンclick
      onRemove: function(e) {
          this.model.destory();
      },

      // destory
      remove: function() {
           this.$el.remove();
      }
});

===========================================
var bookModel = new Bookl({
     title: "javascript mvc",
     price: 2000
});

var bookView = new BookView({
     model : bookModel
});
bookView.render();
History / Router
History
pushStateに対応
location.hashへ自動でフェイルオーバー
Router
URL (location.hash)に基づいた処理のルーティング
var BookShelfRouter = Backbone.Router.extend({

      routes: {
          "home":      "home",
          "search/:query": "search"
      },
      home: function() {
          ・・・
      },
      search: function(query) {
          ・・・
      }
});

var router = new BookShelfRouter();
Backbone.history.start({pushState: true, root: "/home"})

============================
http://hoge/seach/mvc
良いところ
・LinghtWeight
  1431行(v.0.9.2)、 pack & gzipで5.6KB
 最小構成(zepto + underscore)で
  5.6KB + 4KB + 8.4KB = 18KB

・RESTFul JSON

・Routing & History Control
今後
● backbone conf 2012 (5/30-31)

● リアクティブプログラミング
  backbone.io
  node.js + socket.ioでserver sideのmodelと
 リアルタイムに連携

Backbone.js