client-side javascript

JavaScriptのすごく初歩的なことでよくわからないので整理する。よくわかってなくてすごい恥ずかしい感じがするけど書いたら誰か何か教えてくれそうだし書く。client-sideのJavaScriptは、未だあまりよく分からずにもやもやしながら適当に書いてる。もやもや感が説明したいけどなかなか説明しづらい。

こういうタブをJavaScriptを使って実装する例を考える。タブをクリックすると、そのタブに切り替わるというやつ。

HTML

CSS

JavaScript Pattern 1

深く考えずに素朴に実装すると、こういう感じになる。clickイベントに与える無名functionの中に全部詰め込む。こういう風に書いてるJSのコードはよく見る。こういうの大量に書くのはすごい簡単だけど大量にこういうのが書かれてたら読むの辛い感じがする。

懸念

例えばこれまでRubyでコードを書いていたときは、基本的なことを守ってれば大体綺麗に書けていた。1つのメソッドが1つの仕事をするように努力して書く。その仕事に正しい名前を付ける。ローカル変数が沢山出てきたら嫌なコードの匂いがするので、もっと分けられないか考える。でもJavaScriptを書いていると、そういう風に細かく処理を分割するのが難しそうだし、あんまりそういう風に上手くやってるコードを見かけない。特にクラスを利用して書いていないから、インスタンスメソッドに分けるとかそういうことができない。じゃあ手続き型っぽくfunctionに分ければ良いかと言えば、分けたところであまり綺麗になりそうにない。各functionの中でfunctionの外側の変数を沢山参照する羽目になって、色々な箇所からの色々な変数への参照が散らばり、すごく整理しづらくなる。そういう風にクロージャとしてfunctionの外側を参照するのではなくて、それらの必要な変数を全て引数で渡すという方法もあるけど、手続き型の読みにくいコードみたいになってしまう。

理想はやはりオブジェクト指向っぽく考えたくて、オブジェクト指向っぽく書きたいというよりはオブジェクト指向っぽく考えたくて、何らかの概念を与えられたオブジェクトがそれぞれ自分の責任範囲の実装だけを知っていて、他人の仕事だと思うものは適切な相手にメッセージを投げ、それぞれのオブジェクトが互いに協調動作することで勝手にシステムが動いていく、というのが良い。適切なオブジェクトに適切な責任範囲の役割を実装してあげれば勝手に動くというのが、一度に全体のことを把握すること無く、常に1つのオブジェクトの責任のことだけ考えながら実装できていい。

client-sideのJavaScriptであまりコードの形を変えずにそういう風に考えるにはどう捉えたら良いかというのをずっと考えてる。クラスをcssのclass、インスタンスをcssのclassが与えられたDOM、メッセージ(メソッド)をDOMのイベント、みたいに考えると上手くいかないかなとか思ってた。

タブの例で言えば次のようなことを考えてる。タブの中のa要素はクリックされたことをタブに通知する責任を持つ。タブに通知して実際にどうなるかということは知ったことではない。タブは、表示すべきタブを表示する責任と、対応するコンテンツに変更を通知する責任を持つ。こちらもコンテンツに通知したあと実際にコンテンツがどう変化するかということまで知っている必要はない。コンテンツは、表示すべきコンテンツを表示する責任を持つ。

JavaScript Pattern 2

実装してみるとこういう感じになる。イベントが来たら、自分の責任範囲だけ処理して、あとは適切な相手に適切なイベントを伝播させる。

JavaScript Pattern 3

タブがクリックされるたびにjQueryオブジェクトを生成したりDOMツリーを走査したりという処理コストのことが気になるなら、もう少し最適化する。

おわり

結局どういう風に書いて良いのか分からずに震えながら書いてる。
皆さんclient-sideのJavaScriptどういう風に書かれてますか。

追記

@r7kamura OOっぽくしたやつ(coffee) bit.ly/RFuxwH

— 高意識エネルギー体さん (@mizchi) 10月 18, 2012