このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
なんか継承で長々とやってるな。もう一息。
プロトタイプを継承する方法は分かった。
プロトタイプには、主にメソッドが登録されているため、
親クラスのメソッドを継承することができる。
では、インスタンスプロパティなど、
プロトタイプに定義されていないものを
親クラスから継承するにはどうすればよいか。
Java や C# では、派生クラスのコンストラクタから、
基底クラスのコンストラクタを呼び出すことで、
基底クラスが持つインスタンスフィールドの値を継承する。
JavaScript でも考え方は同じだ。
function MixiError(message) {
// Error のコンストラクタを呼び、
// this を初期化したい
Error(message); // ?
}
残念ながら、上記ではうまくいかない。
単純に Error に括弧をつけて呼び出した場合、
通常の関数呼び出しとなってしまうので、
this として MixiError インスタンスを渡すことができない。
だからといって、new Error(~) とすると、
Error の新しいインスタンスが作成されてしまい、
その戻り値は MixiError のインスタンスにならない。
JavaScript の関数オブジェクトには、
こういう用途に使うための、
call メソッド(プロパティ)がある。
そう、「関数オブジェクトが持つメソッド」だ。
call メソッドは、第 1 引数にオブジェクトを取る。
第 2 引数以降は、本来の関数が持つ引数と同じである。
第 1 引数として渡したオブジェクトは、
関数の内部で、this として参照することができる。
つまり、this を明示することができるのである。
ややこしいので、書いて比較してみよう。
●Error("message")
Error 関数が受け取る引数は文字列 "message"。
Error 関数内の this は、グローバルオブジェクトを指す。
●new Error("message")
Error 関数が受け取る引数は文字列 "message"。
Error 関数内の this は、新しい Error インスタンス。
●Error.call(object, "message")
Error 関数が受け取る引数は文字列 "message"。
Error 関数内の this は、object。
では、call メソッドを使って、
MixiError コンストラクタを書いてみよう。
function MixiError(message) {
// Error インスタンスとしての初期化
Error.call(this, message);
}
MixiError のインスタンスである this を、
Error コンストラクタにそのまま渡すことで、
Error インスタンスとしての初期化を行うのだ。
「理論的」にはこれでうまくいく。
理論的と書いたのには意味がある。
仕様上では、Error コンストラクタは
message の引数を 1 つ取り、
undefined でなければ、新しいインスタンスの
message プロパティに文字列として格納するとある。
しかし、Internet Explorer や、FireFox では、
上記コンストラクタで作成した MixiError インスタンスの、
message プロパティが設定されていないようだ。
つまり、Error コンストラクタが旨く機能していない。
まあ、Error 型は組み込み型であるので、
その実装方法は実行環境によって異なる。
なので、派生コンストラクタが、Error コンストラクタを
call で呼び出すことを想定していない可能性もある。
なので、MixiError コンストラクタに関しては、
ちゃんと初期化も行った方がよさそうである。
function MixiError(message) {
// Error インスタンスとしての初期化
Error.call(this, message);
// MixiError インスタンスとしての初期化
if (message !== undefined) {
this.message = String(message);
}
}
自分で設計したクラスから派生させる場合は、
派生クラスのコンストラクタ内で、
call で基底クラスのコンストラクタを呼ぶことで、
インスタンスプロパティの継承を実現することができる。