prototype.js

ためしでprototype.jsを使ったプログラミングを仕事で使ってみて、非常に低レベルな部分で躓き気づいたこと。


prototype.jsで、Class志向的なプログラミングをして、そのコンストラクタ(initialize)でHTML内のDomエレメント等部品を参照する場合($()関数又はgetElementById())、あくまでそのコンストラクタは全てHTMLがロードされた後で呼び出されなければならないという事。


当たり前のことなのだが、しばらくJavaScriptのプログラミングから遠ざかっていた為に最初気づかなくてかなり悩んでしまった。


通常、ヘッダ部分でprototype.jsJavascriptのプログラム自体を宣言しインポートする。これはおそらくヘッダで記述した順番、つまりscriptタグで宣言した順番で読み込まれる。
例えば、上記の様にClassのコンストラクタで外部のHTMLエレメントオブジェクトを参照する場合、コンストラクタの引数で渡したり、直接、コンストラクタの中で参照したりしてインスタンス変数の中に格納するような記述をしている場合、そのClassをnewする場所がヘッダ内の場合、まだHTMLのdocumentオブジェクト自体が読み込まれていないので、存在しないものへの参照になってしまう。
例えば、コンストラクタの中で、その参照したエレメントに対してイベントをEvent.observe等でバインディングする場合にエラーが発生する。


ではどうするかと言うと、一番良い手は、documentが全てload完了した時点でそのクラスをnewするということである。
つまり、HTMLのbodyタグのonloadでinit()等の初期化関数をイベントハンドラ関数として設定して、そのinit()の中でそのクラスを初期化するわけである。
又は、ヘッダ内のscriptのなかで、
window.onload = init;
とかしてやるとか、Event.observeしてやっても良い。
但し注意が必要なのは、loadイベント等に割り当てられるのは関数(function)でコンストラクタ等は直接渡せないということと、windowのプロパティonloadに初期化関数を設定する場合、一個の関数しか割り当てることが出来ず、複数書いた場合は上書きされるということである。
その点、bodyタグのonloadで関数を指定する場合は、
<body onload="funcA(); funcB(); func();”>
とかできる。
しかし、これは便利であるが、自分的には、あまりHTML内にスクリプトのハンドラとか記述するのは好きでない。
やはりXHTMLの記述は完結に構造だけを記述すべきである。
JavaScriptはヘッダの中だけで完結させたい。


と言うことで、そのページに必要なスクリプトの初期化作業はヘッダ内で、windowオブジェクトのloadイベントにバインドする形で一つだけ設定して動くようにjavascript自体を設計することが一番きれいだと思う。
出来れば一つのクラスをnewしてやるだけでOKなのが一番だけど、これも時と場合によると思う。


prototype.jsを使ってプログラミングすると、割ときれいにコードをまとめることが出来るようです。