JavaScript The Good Partsを読む
JavaScriptを書く機会というのは、WEBアプリケーションエンジニアとしては画面の動的な制御だとかAjaxだとか、そういった用途で使うことが多いだろう。ともするとさほど高いレベルは必要なく割と「誰でも書ける言語」的な過小評価をされていることもしばしば。
でも実はJavaScriptって奥が深い言語で、いろんな表現方法をもっていて、コードの自由度が高くて、ちょっとトリッキーな感じになっちゃったりするところが趣味プログラマに好かれてたりもする。
そういうわけでこの本読んだ。
20代くらいでコーディングメインの若手WEBエンジニアが読むと「へーそんなんあったのか!」みたいな具合でそこそこ楽しめるんではなかろうか。
JavaScript The Good Parts / ダグラス・クロフォード著
そもそもの話
表題であげた通り、JavaScriptでprivateな変数とか関数を表現する方法を考えていきたいが、そもそもなんでprivateな変数とか関数が必要なわけ?って疑問がでてきた方はオブジェクト指向のアクセス権について勉強してくれよな。
詳しいことは割愛するが、publicとprivateを区別することでコードの意図が明確になり読みやすくなるというようなメリットがある。特にチームで仕事する場合はね。
クロージャという手段
これを表現するには「クロージャ」と呼ばれるテクニックを使う。クロージャとは…説明したいところだが、文章で説明するにはやや難があるものだから実例から理解するといいだろう。
失敗例1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<html> <head> <script type="text/javascript"> // ダメな例。小学生に戻ってJavaScript勉強してこい。 var myobj = function() { var hoge = "hoge"; this.moge = "moge"; this.poge = function() { alert("poge"); } }(); alert(myobj.hoge); // undefind alert(myobj.moge); // undefind myobj.poge(); // undefind alert(window.moge); // "moge" </script> </head> <body></body> </html> |
これはそもそもJavaScriptの言語仕様をまるで理解してないと言える。
末尾に()がついているので右辺の関数の実行結果を変数myobjに代入するという命令になる。当然returnしていないので戻り値はundefined。myobjのメンバにアクセスしようとしても不可能だ。
そして実はこのコードの悪いところはもうひとつある。this.mogeのようにthisのメンバに代入しようとしている箇所だ。この場合、thisが示すのはグローバル領域になるため、window.mogeに代入されてしまい、悪しきグローバル汚染を引き起こす。
失敗例2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<html> <head> <script type="text/javascript"> // 一見正しい挙動に見えるが実は勘違い君。 var myobj; (function() { myobj = function() { var hoge = "hoge"; this.moge = "moge"; this.poge = function() { alert("poge"); } return this; }(); })(); alert(myobj.hoge); // undefined alert(myobj.moge); // "moge" myobj.poge(); // "poge" </script> </head> <body></body> </html> |
これは実際にぼくがやってしまった勘違いコードだ。これで期待している挙動を実現できるのだが可読性は著しく低い。このコードは失敗例1を無理矢理にカバーしているだけである。下記のローカルスコープを利用することでthisが示す値を操作しているだけなのだ。
1 2 3 4 |
// ローカルスコープ (function() { 〜 })(); |
つまりthisが示す値はローカルスコープとなる。myobjにオブジェクトのインスタンスを代入しようとしているつもりが、実際にはローカルスコープが返されているという状態になり、人が認識しやすい「オブジェクト」という表現から外れてしまう。
正しい例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<html> <head> <script type="text/javascript"> // クロージャを利用した簡潔な表現 var myobj = function() { var hoge = "hoge"; var moge = "moge"; var poge = function() { alert("poge"); } return { getMoge: function() { return moge; }, poge: poge } }(); alert(myobj.hoge); // undefined alert(myobj.getMoge()); // "moge" myobj.poge(); // "poge" </script> </head> <body></body> </html> |
右辺の関数の実行結果をmyobjに代入する。関数内で定義されたhoge, moge, pogeはfunctionのスコープに縛られることになるので外側からは参照できなくなる。そこで、外側からアクセス可能にするために、return部でmoge, pogeにアクセスしている関数(変数)を持ったオブジェクトを返している。hogeにアクセスする関数は用意していないので、これでhogeは完全にprivateな変数となる。
シンタックスシュガー
昨今ではCoffeeScriptやTypeScriptといったようなシンタックスシュガーが台頭してきている。ぼくもCoffeeScriptを使ったことがあるが、非常に使いやすい。記法もやさしいし、コンパイル後のコードを見るとJavaScriptの悪い部分をうまくカバーしてくれている(グローバル汚染の回避や==比較演算子の問題など)。
今後はこういったシンタックスシュガーが主流になり、生のJavaScriptを書く機会は減るだろうなーと思うと、嬉しくもありちょっとさみしくもある、そんな心境になったりしてね。

原田 敦

最新記事 by 原田 敦 (全て見る)
- Rails Engineでブログ機能追加するgemを作る - 2015年3月15日
- WEBエンジニア一人だけでサービスを作りきる方法-夫婦のための自動ごはん予定お知らせサービス「GoHaaan」制作でやったこと - 2015年3月7日
- CentOS6でMariaDBのDynamic Columnsを試してみた - 2015年2月28日