警告:これは長い投稿です。
シンプルにしましょう。JavaScriptでコンストラクターを呼び出すたびにnew演算子にプレフィックスを付ける必要はありません。これは、私がそれを忘れがちであり、私のコードがひどく失敗するからです。
これを回避する簡単な方法はこれです...
function Make(x) {
if ( !(this instanceof arguments.callee) )
return new arguments.callee(x);
// do your stuff...
}
しかし、変数noを受け入れるにはこれが必要です。このような引数の...
m1 = Make();
m2 = Make(1,2,3);
m3 = Make('apple', 'banana');
最初の即時解決策は、このような「適用」方法のようです...
function Make() {
if ( !(this instanceof arguments.callee) )
return new arguments.callee.apply(null, arguments);
// do your stuff
}
ただし、これは間違っています。新しいオブジェクトはapply
コンストラクタではなくメソッドに渡されますarguments.callee
。
今、私は3つの解決策を思いつきました。私の簡単な質問は次のとおりです。または、より良い方法がある場合は、それを教えてください。
最初 – eval()
コンストラクターを呼び出すJavaScriptコードを動的に作成するために使用します。
function Make(/* ... */) {
if ( !(this instanceof arguments.callee) ) {
// collect all the arguments
var arr = [];
for ( var i = 0; arguments[i]; i++ )
arr.push( 'arguments[' + i + ']' );
// create code
var code = 'new arguments.callee(' + arr.join(',') + ');';
// call it
return eval( code );
}
// do your stuff with variable arguments...
}
2番目 -すべてのオブジェクト__proto__
には、そのプロトタイプオブジェクトへの「秘密」リンクであるプロパティがあります。幸いなことに、このプロパティは書き込み可能です。
function Make(/* ... */) {
var obj = {};
// do your stuff on 'obj' just like you'd do on 'this'
// use the variable arguments here
// now do the __proto__ magic
// by 'mutating' obj to make it a different object
obj.__proto__ = arguments.callee.prototype;
// must return obj
return obj;
}
3番目 –これは2番目のソリューションに似ています。
function Make(/* ... */) {
// we'll set '_construct' outside
var obj = new arguments.callee._construct();
// now do your stuff on 'obj' just like you'd do on 'this'
// use the variable arguments here
// you have to return obj
return obj;
}
// now first set the _construct property to an empty function
Make._construct = function() {};
// and then mutate the prototype of _construct
Make._construct.prototype = Make.prototype;
eval
解決策は不器用で、「悪の評価」のすべての問題が伴います。__proto__
ソリューションは非標準であり、「mIsERYの素晴らしいブラウザ」はそれを尊重しません。3番目の解決策は過度に複雑に思えます。
しかし、上記の3つのすべてのソリューションを使用すると、このようなことができます。
m1 = Make();
m2 = Make(1,2,3);
m3 = Make('apple', 'banana');
m1 instanceof Make; // true
m2 instanceof Make; // true
m3 instanceof Make; // true
Make.prototype.fire = function() {
// ...
};
m1.fire();
m2.fire();
m3.fire();
事実上、上記のソリューションは変数noを受け入れる「真の」コンストラクターを提供します。の引数を必要としませんnew
。これについてどう思いますか。
-更新-
「エラーを投げるだけ」と言っている人もいます。私の回答は次のとおりです。10以上のコンストラクタで重いアプリを実行しているので、すべてのコンストラクタがコンソールにエラーメッセージをスローすることなくその間違いを「スマートに」処理できると、はるかに使いやすくなると思います。
Make()
せずにnew
メイクが大文字であるので、それはそれはコンストラクタであると仮定しているため
new
か?後者の場合、おそらく間違ったサイトを尋ねているからです。前者の場合、新しいエラーの検出とエラーの検出に関する提案をすぐに却下したくない場合があります。アプリが本当に「重い」場合、最後に望むのは、速度を落とすための過剰な構築メカニズムです。new
、それが得るすべてのフラックのために、かなり迅速です。