トップページ上に情報をモリモリ書きたくなかったので、どこがポイントやな?って話になりますが、左サイドの装飾と、左クリックによるポップアップメニュー、そしてそれらにかけられる影のエフェクトでしょうか。プログラム的には、裏でクラスの継承やらをちょっといい感じに自前で実装してたりします。サブクラスのコンストラクタ内で
this._super();
とやれば、スーパークラスのコンストラクタが呼ばれるようにしています。継承するたびに、各スーパークラスのコンストラクタを保存していき、_superで正しいコンストラクタを呼び出せるようにしないといけない箇所がちょっと大変でしたが。
つまり、クラスAのスーパークラスがBで、BのスーパークラスがCだとしておきますと。
// prototype.jsのClass.create()使っているのでinitialize
B.prototype["_super"] = C.prototype.initialize;
として置き、B.prototype.initialize内で
this._super();
を呼ぶとします。Bを継承してAを定義したときに、
A.prototype["_super"] = B.prototype.initialize
として、A.prototype.initialize内で
this._super(); // これはB.prototype.initializeだが...
を呼びます。B.prototype.initialize内でもthis._super()を呼んでいるわけですが、この_superはA.prototype._superの事になってしまっているので、再びB.prototype.initializeを呼んでしまい...無限ループになります。
これを回避するために、FunctionクラスのtoStringメソッドでソースへ落とし込み、_super()を_super0()というように重複しないように書き換えます。もちろん、B.prototype["_super"]にクラスCのコンストラクタを代入するのではなく、
B.prototype["_super"+B.__INHERITANCE_NUMBER] = C.prototype.initialize;
// B.__INHERITANCE_NUMBER = 0
としてやります。この__INHERITANCE_NUMBERは継承回数-1としておき、継承を行うたびにカウントアップしていけば、_superが書き換えられずにきちんと保存されているように見えます。
ソースコードへ落とし込んだ後、Firefoxではeval()してやれば関数オブジェクトを返してくれたのですが、IEでは何も返してくれません。だもんで、無名関数を定義して、そのなかで上記のthis._super0の中身を実行するようなevalを書いてやらなければなりませんでした。この無名関数を、B.prototype["_super0"]に代入してやればOKです。
スーパークラスが何かが分かっているんだから、いちいち_superを自動で定義してやらなくても、手で書けばいいじゃないか、という話になるのですが、こっちの方がエレガントかなぁとか思いまして(笑)変数(名)がクラス(名)のように扱われるので、
var D = C;
とやれば、C言語でいうtypedefが簡単に出来てしまいます。ので、スーパークラスのコンストラクタ呼び出しも、上記のようにスーパークラスに別名をつけるような処理を行っておけば、長いクラス名でも手で打つのは全然面倒ではありません。
まぁ、あくまで自己満足と勉強のためにわざわざ、スーパークラスへのアクセスキーワードを定義したりしているわけです。JScriptだったらsuperキーワードが定義されていたような気も。
ちなみに現在は、スーパークラスのコンストラクタ呼び出し以外にも、スーパークラスのメソッド呼び出しも可能にしたいとか思っておりまして。overrideしたメソッドから、overrideされた元々のメソッドを呼びたい時に、Perlみたく、$obj->SUPER::method()と書きたいわけでして。Firefoxだったら動くのにIEだと動かない!という状況に再び遭遇したので、もう少しこの問題と格闘しそうです。
No comments:
Post a Comment