knockoutの基礎知識

    この記事は、knockout.js Advent Calendar 2015の１日目の記事です。
    knockout , knockout-es5 , knockout.punches環境を想定しています。

[![knockout](https://qiita-image-store.s3.amazonaws.com/0/58195/bea6c9e5-a60d-ffb5-fe9b-c15d901983d0.png)](http://knockoutjs.com/)

[knockout.js](http://knockoutjs.com/) は、MV*系のライブラリです。そのなかでもMVVM(Model View ViewModel)という分類になります。

knockoutは基本的にフレームワーク（特にフルスタックフレームワーク）では__ありません__。あくまで**ライブラリ**です。
その為、フレームワーク独特の文化・世界観にどっぷりつかる必要はなく、任意の他のライブラリとの連携が比較的楽なメリットがあります。
逆にデメリットとしては、MVVMの仕組み以外の機能（例えば、SPAなどで用いられるクライアントサイドのWebRoutingの仕組みなど）は提供されていません。　完全に路線（レール）を引いてほしい場合には、AureliaやAngular2などを利用するのがいいでしょう。



knockoutは*2way-binding*の仕組みを提供しているので、
　とあるModelの
　とあるPropertyの変更を検知し、
　その変更をもとに、
　　即座または[任意の遅延後](http://knockoutjs.com/documentation/rateLimit-observable.html)に、
　　　他のプロパティを変化させたり、
　　　Viewを更新したり出来ます。

実際の[サンプル](http://jsfiddle.net/MKGaru/x8au51uy/)を見てみましょう。

---------------------------------------------------------------------

#### [knockout標準記法でのサンプル](http://jsfiddle.net/MKGaru/x8au51uy/)

```html:index.html
あなたの名前は？:<input type="text" data-bind="value:myName">

<div>こんにちは！<span data-bind="text:myName"></span>さん</div>
<div>このページの滞在時間は、<span data-bind="text:age"></span>秒です</div>
```

```js:script.js
var vm = {
    myName: ko.observable("山田"),
    age: ko.observable(1)
}
setInterval(function(){
    vm.age( vm.age()+1 );
},1000);
ko.applyBindings(vm);
```

---------------------------------------------------------------------

``ko.applyBindings(vm)``は、ViewとViewModelの紐づけです
[この例](http://jsfiddle.net/MKGaru/x8au51uy/)では、
　　ユーザの名前 をView→ViewModelへbindingしていて、
　　滞在時間を ViewModel→Viewへbindingされているのが確認できます。

knockoutの構文拡張
-----------------
ただ、ちょっと書き方が古臭い　とか　面倒だ　とか感じるあなたは現代っ子な感覚の持ち主でしょう（いい意味で）。
それもそのはずで、knocckoutは ~~悪名高き~~ [IE6にも対応する](http://knockoutjs.com/documentation/browser-support.html)ために、[モダンな記法](https://www.google.co.jp/search?q=ecmascript5%20javascript)を標準では採用していません。

しかし、そんな古代のブラウザを[サポートする必要がない](https://support.microsoft.com/ja-jp/gp/microsoft-internet-explorer)、またはそもそもIEではなく、ChromeやFirefoxもしくはスマホなどのモダンブラウザのみにターゲットを絞れる場合には、どんどんモダンな記法を採用して行きたいです。
  
そこで、標準のknockoutを次の２つで拡張します。

* [knockout.punches](https://mbest.github.io/knockout.punches/) 
  (knockoutの構文の構文糖衣（SyntaxSugar)を提供)
* [knockout-es5](https://github.com/SteveSanderson/knockout-es5) 
  (ECMAScript5を使用したObjectのPropertyの[Getter Seter](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)をknockoutのobservaleとして利用する仕組みを提供)

[先ほどのサンプル](http://jsfiddle.net/MKGaru/x8au51uy/)に、拡張した仕組みを適用すると　[**このように**](http://jsfiddle.net/MKGaru/4Lhsfbs4/)　すっきりします。

```html
あなたの名前は？:<input type="text" data-bind="value:myName">

<div>こんにちは！{{myName}}さん</div>
<div>このページの滞在時間は、{{age}}秒です</div>
```

```js:script.js
var vm = {
    myName: "山田",
    age: 1
};
setInterval(function(){
    vm.age++
},1000);

ko.track(vm);
ko.punches.enableAll();
ko.applyBindings(vm);
```

新たに追加された２行について、  
　``ko.punches.enableAll()``は、
　　　[knockout.punches](https://mbest.github.io/knockout.punches/)で追加されるあらゆる構文糖衣を有効にし、
　``ko.track(vm)``は、
　　　[knockout-es5](https://github.com/SteveSanderson/knockout-es5)により追加されるもので、vmのもつプロパティを監視対象に追加する（≒各プロパティをobservable()でマッピング）
といったものです。

>（各ライブラリは、自前のサーバで提供するか、　CDNとして提供されているものを利用するようにしてください。　JsFiddleのサンプルで用いているような rawgithub.com　への直リンでの本番運用は禁止されています。）