Entries

ストリングからクラスのインスタンスを作る

ちょっと個人的にやってる実験に、BeIntaractiveさんのECMAインタプリターを導入しようとしてるのだけど、一点困ってることが。

ビルトインクラスのnewは何だかコンストラクタの呼び出しがうまくいかず・・・。ビルトインクラスを使いたい人は、ファクトリメソッドを作ってエクスポート(後述)して使ってください。

という奴です。なんだかんだでクラスが必要になる度にファクトリを作るのも凄く骨なので、ちょっと乱暴に万能ファクトリを作ることにした。


//Stringから無理やりクラスインスタンスを作成
function createInstanceFromString(classPath:String){
var classRef:Object = eval(classPath);
return new classRef();
}

こうすれば、ストリングでクラスのフルパスを渡すだけでお好きなインスタンスが取得できそう。超楽チン。ただ問題は、この方法じゃあコンストラクタにパラメータを渡せないこと。多分applyが使えないので。

んで、うんこら悩んだ末に、以下のように解決することにした。


function createInstanceFromString(classPath:String, params:Array){
var classRef:Object = eval(classPath);
switch( params.length){
case 0:
return new classRef();
case 1:
return new classRef(params[0]);
case 2:
return new classRef(params[0],params[1]);
...
case 20:
return new classRef(params[0],params[1]...params[19]);
default:
throw new Error("createInstanceFromString:パラメータ大杉"+classPath + " " + params.length);
}
}

無理矢理パラメータの数で分岐してコンストラクタに値をぶち込む(←超馬鹿)。自分の知る限りビルトインクラスの引数最長はColorMatrixFilterの20個なので、それを踏まえてこんなswitch文を考えた。switchなしでundefined上等で20個注入しちゃえって気もするけど、それだとコンストラクタ内でarguments.lengthとか使ってたら誤動作する可能性が高い。

複雑な機構作るよりは速度も出るだろうし、なにより実装時間が10分以下ですむ。
泥臭い上に、そこはかとなくデンジャラスな気もしますが、隠蔽しちゃえば大丈夫でしょう・・・多分。

うーん、しかしもっとエレガントな方法とかってないかなぁ。

<追記>
BeInteractiveさんがやってくれました。存在だけは知ってたけど__bytecode__って実用可能なもんなんだなぁ、とビックリ。
ありがとうございますです。