Backbone.js をちょっとだけさわった

JS でMVC的に切り分けるということをちょっと学びたかったのですこし触った。具体的に触発されたのはタイミングもあるけど、 フロントエンドJavaScriptにおける設計とテスト をみたってのもある。

なにがしたいかって、JS において DOM 操作はともかく、ロジック部分はテストしたいんだよね。テストがないとリファクタリングするときに不安になる。

参考資料

件のスライドの @hokaccha さんの PixelGrid 社の CodeGrid を参考にした。この記事を書いた後にドットインストールの講座が出てきたから、今からだったらそれを見るのもいいかもしれない。

簡単なチュートリアル

面倒なので HTML はこんな感じ

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>

  <script type="text/javascript" src="./underscore.js" charset="utf-8"></script>
  <script type="text/javascript" src="./jquery-1.7.1.js" charset="utf-8"></script>
  <script type="text/javascript" src="./backbone.js" charset="utf-8"></script>
  <script type="text/javascript" src="./backbone.localStorage.js" charset="utf-8"></script>

</head>
<body>
backbone.js!
<ul class="todoList"></ul>
</body>
</html>

で、肝心の内容。本当は通信もみてみたかったけど、サーバーたてるの面倒なので backbone.localStorage を使用した。

// model の生成
var Todo = Backbone.Model.extend({
  name: null,
  localStorage: new Store("todos")
});
// model の集合である collection を生成
var Todos = Backbone.Collection.extend({
  model: Todo
});
// model のインスタンスを生成
var todo1 = new Todo({name: 'hoge'});
var todo2 = new Todo({name: 'moge'});
var todo3 = new Todo({name: 'toge'});
var todo4 = new Todo({name: 'ea'});
// collection のインスタンスを生成
var todos = new Todos();
// collection に model をつめこむ
todos.add([todo1, todo2, todo3, todo4]);

// UI コンポーネントと考えるといい。これは子要素の li タグ
var TodoListItem = Backbone.View.extend({
  tagName: 'li',
  // options ってつけるのが慣習っぽいけど、中身は object(dict) だよねっていう
  initialize: function (object) {
    // で、object のプロパティを指定して加える
    this.$el.text(object.text);
  }
});

// こっちは親要素の ul をとってくる
var TodoList = Backbone.View.extend({
  el: '.todoList',
  add: function (text) {
    // {text: text} ってのも微妙だけど、text プロパティに引数 text を加えるという話
    var item = new TodoListItem({text: text});
    this.$el.append(item.el);
  },
  collection: todos
});

// View のインスタンスを生成する
var todolist = new TodoList();

todolist.add('a');
todolist.add('b');
todolist.add('c');
todolist.add('c');

var TodoList = Backbone.View.extend({
  initialize: function() {
    this.collection.on('add', this.add, this);
  },

  add: function(todo) {
    var item = new TodoListItem({ model: todo });
    this.$el.append(item.el);
  }
});

雑感

Sencha Touch をガリガリやってて、「ああそういうことか」ってのが腑に落ちた。感覚としては「model, collection でデータを扱う。View で UI コンポーネントを生成する。それぞれは分離している」という感じ。だから疎結合にしやすい。ということなんだろう。

Event と Router は調べたけど触ってはいない。ただ、history.pushState とかつかっていい感じにしてくれるのは楽そうだね。

ちなみに

Sencha Touch で Ajax 通信してしまうとき idProperty がついてしまったりしてそれが API 仕様とあわなかったりするのは Backbone.js でもある話で、通信部分の URL の組み立ては結局自前でやる必要があったりする。GET, POST はいいけど PUT, DELETE とかを使うか否かってのもオプションにある。

あと AugularJS についてもちょっとだけドットインストールでみたりした。あれはもうちょっとライトなMVCのかたちなんだろうか?個人的には JSON 受け取ったら組み立てるだけって感じで、たしかにお手軽なんだけど本格的にサイトを組もうとすると大変そう。逆に言うと単純なサイトをお手軽につくるときには楽そう。

まあ

Backbone.js をつかって仕事する機会はそんなにないと思うけど、得るものはあったなという感じ