Kanasan.JS レポート ― 2007年11月04日 14時23分
関西での JavaScript 勉強会、Kanasan.JS に行ってきた。内容は Prototype.js のコードリーディング (バージョン 1.5.1.1 を使用)。「家に帰ってレポートを書き、主催者のブログにトラックバックを送るまでが勉強会です」と念を押されたので、まもなく Kanasan さんの記事経由で参加者各々の様子をうかがえるようになると思うけど、以下あとから思ったことも加えて私の場合をつらつらと。
JavaScript 概説 & コードリーディング
プロトタイプ
やはり皆さん一番引っかかるのはここみたい。おそらく、プロトタイプと名のつくものが 2 つあるのが混乱の原因だと思う。
prototype
プロパティ- 関数 (Function オブジェクト) のみが持つ。その関数をコンストラクタとして使ったときに用いられる。
[[Prototype]]
内部プロパティ- すべてのオブジェクトが持つ。プロパティ / メソッドを参照するときは、自分自身、自分の
[[Prototype]]
内部プロパティに指定されているオブジェクト、さらにその[[Prototype]]
内部プロパティに指定されているオブジェクト、……といった具合に、そのプロパティ / メソッドが見つかるまでプロトタイプチェーンをたどることになる。内部プロパティなので普通に JavaScript コードを書いているときに参照はできないが、__proto__
プロパティとして公開している実装 (Firefox で使われている SpiderMonkey、Safari で使われている JavaScriptCore など) もある。
prototype
プロパティと [[Prototype]]
内部プロパティの関係については、私も以前 JavaScript の new 演算子の意味で少し触れたほか多くの解説記事があるし、これを押さえておくと JavaScript の理解がぐっと進むと思う。Prototype.js を読む上でも、今追加しているのがいわゆるクラスメソッドなのかインスタンスメソッドなのかといったことがわかりやすくなるだろうし。
レキシカルスコープとダイナミックスコープ
JavaScript はレキシカルスコープを採用。関数内で定義されていない変数が実際にどの変数を指しているか、静的に (コンパイル時に) 決定できるのがレキシカルスコープ、実行時にならないとわからないのがダイナミックスコープ。
Perl でいうと、my
で定義された変数 (Private Variables via my() の項) はレキシカルスコープを持ち、local
で定義された変数 (Temporary Values via local() の項) はダイナミックスコープを持つ (個人的には my と local どう違う? - futomi's CGI Cafe の例がわかりやすかった)。Common Lisp はレキシカルスコープだが、Emacs Lisp は (レキシカルスコープにすると重くなるから) ダイナミックスコープらしい。
Opera オブジェクト
Prototype.js ではブラウザが Opera かどうかの判別に window.opera
の有無を用いている。Opera では Opera オブジェクトが window.opera
プロパティの値。Opera オブジェクトは、"9.23"
といったバージョンを文字列で返す version
メソッドなどを持つ。
Prototype.K
名前の由来が謎。K コンビネータ説は motemen さんより。やってることは恒等関数だから個人的には id
とするのが一番しっくり来るんだけど、それだと document.getElementById
と紛らわしいか。
Number.prototype.times
Ruby の Integer#times
から。ただし、5.times(func)
とやると 5.
までが数値リテラルとみなされるので構文エラーになる。(5).times(func)
、5..times(func)
、5 .times(func)
などなら大丈夫。
String.prototype.gsub
Ruby の String#gsub
から? 機能的には組み込みの String.prototype.replace
とそう変わらないと思うけど、Ruby とインターフェースを合わせる、独自のテンプレート書式を使う、ブラウザのバグを避けるといった目的でわざわざ定義しているのではないか。
暗黙の型変換
数値型への変換では、null
は 0
、undefined
は NaN
として扱われる。null * 2
は 0
。var x = null; x--;
とすれば、x
が数値として評価され、最終的に x
の値は -1
になる。比較演算子における型変換規則、等価演算子における型変換規則は非常にややこしいので、できるだけ暗黙の型変換が起こらないようにしたほうがいいかも。
inject
症候群
簡単なループで書けるところも、わざわざ Enumerable.inject
(Ruby の Enumerable#inject
から。JavaScript 1.8 の Array.prototype.reduce
) を使っているのではという疑惑が発生。そのほうがわかりやすいという声が挙がるも、変態の意見と一蹴される。
String.prototype.succ
単に Unicode のコードポイントが次の文字を求めるだけ。Ruby の String#succ
のように "9"
を "10"
にしたり (Perl でいうマジカルインクリメント) はしない。
String.prototype.underscore
"::"
を "/"
にするなど、名前以上のことをやりすぎ。
雑感
顔を付き合わせてひとつのコードについて話し合うというのは初めてだったけど、すごく楽しかった。何より良かったのは、Ruby をはじめとしてほかの言語に堪能な方の見地を聞けたこと。普段と違った視点から JavaScript を眺めることができ、新鮮な気分を味わった。次回以降もぜひ参加したいと思う。主催してくださった Kanasan さん、氏久さんはじめ参加各氏に感謝。
それから、お菓子が出るっていうのは非常に大きい。やっぱり人間甘いものがないと生きていけないから。アルフォートとかもう最高。これがあるとないとでは能率が 70% くらい違うと思う。会場前のカレーハウス ガラムの旬の野菜カレーも野菜が山盛りでおいしかった。
ちなみに、Prototype.js からは Ruby の影響が随所にうかがえ、Ruby.js の流れを汲んでいるんだろうなと勝手に思っていたのだけれど、Prototype.js 1.0.0 のソースコードを見る限りでは直接の関係はなかったみたいだ。
コメント
トラックバック
このエントリのトラックバックURL: http://nanto.asablo.jp/blog/2007/11/04/1889765/tb
コメントをどうぞ
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※投稿には管理者が設定した質問に答える必要があります。