24

この質問に対する素晴らしい回答のおかげで、varargsを使用してjavascript関数を呼び出す方法を理解しています。

今私はコンストラクターでapplyを使用しようとしています

この投稿でいくつかの興味深い情報を見つけました。

しかし、私のコードはエラーをスローしています

試行1:

var mid_parser = new Parser.apply(null, mid_patterns);

エラー:

TypeError: Function.prototype.apply called on incompatible [object Object]

試行2:試行1:

var mid_parser = new Parser.prototype.apply(null, mid_patterns);

エラー:

TypeError: Function.prototype.apply called on incompatible [object Object]

試行2:

function Parser()
{
    this.comparemanager = new CompareManager(arguments);
}

mid_patterns = [objA,objB,objC]
var mid_parser = new Parser();
Parser.constructor.apply(mid_parser, mid_patterns);

エラー:

syntax_model.js:91: SyntaxError: malformed formal parameter

試行3:

var mid_parser = Parser.apply(null, mid_patterns);

エラー :

TypeError: this.init is undefined // init is a function of Parser.prototype

当面は回避策があります。

function Parser()
{
    if(arguments.length) this.init.call(this,arguments); // call init only if arguments
}
Parser.prototype = {
   //...
   init: function()
   {
         this.comparemanager = new CompareManager(arguments);
   }
   //...
}

var normal parser = new Parser(objA,objB,objC);

mid_patterns = [objA,objB,objC]
var dyn_parser = new Parser();
dyn_parser.init.apply(dyn_parser, mid_patterns);

これはかなりうまく機能しますが、私が望むほどクリーンで普遍的ではありません。

javascriptでvarargsを使用してコンストラクターを呼び出すことは可能ですか?

4

4 に答える 4

17

thisapplyを使用して、引数として空のオブジェクトを渡すことができます。

var mid_parser = {};
Parser.apply(mid_parser, mid_patterns);

しかし、そのソリューションはプロトタイプチェーンを考慮しません。

演算子を使用して、ただし引数を渡さずにParserオブジェクトを作成してから、コンストラクター関数を再実行するために使用できます。newapply

var mid_parser = new Parser();
Parser.apply(mid_parser, mid_patterns);
于 2009-12-24T18:13:05.633 に答える
11

より良い解決策は、一時的なコンストラクター関数を作成し、必要なクラスのプロトタイプを適用して(プロトタイプチェーンが確実に保持されるようにするため)、コンストラクターを手動で適用することです。これにより、コンストラクターを不必要に2回呼び出すことを防ぎます...

applySecond = function(){
    function tempCtor() {};
    return function(ctor, args){
        tempCtor.prototype = ctor.prototype;
        var instance = new tempCtor();
        ctor.apply(instance,args);
        return instance;
    }
}();

パフォーマンスをテストしたところ、この方法は実際、非常に単純なケースでは少し遅いことがわかりました。ただし、これをより効率的にするには、コンストラクターで単一のDate()オブジェクトを作成するだけです。また、パラメーターが渡されない場合、一部のコンストラクターが例外をスローする可能性があることを忘れないでください。これもより正確です。

私の検証コード:

var ExpensiveClass = function(arg0,arg1){
    this.arg0 = arg0;
    this.arg1 = arg1;
    this.dat = new Date();
}

var CheapClass = function(arg0,arg1){
    this.arg0 = arg0;
    this.arg1 = arg1;
}

applyFirst = function(ctor, args){
    var instance = new ctor();
    ctor.apply(instance, args);
    return instance;
}

applySecond = function(){
    function tempCtor() {};
    return function(ctor, args){
        tempCtor.prototype = ctor.prototype;
        var instance = new tempCtor();
        ctor.apply(instance,args);
        return instance;
    }
}();

console.time('first Expensive');
for(var i = 0; i < 10000; i++){
    test = applyFirst(ExpensiveClass ,['arg0','arg1']);
}
console.timeEnd('first Expensive');

console.time('second Expensive');
for(var i = 0; i < 10000; i++){
    test = applySecond(ExpensiveClass ,['arg0','arg1']);
}
console.timeEnd('second Expensive');

console.time('first Cheap');
for(var i = 0; i < 10000; i++){
    test = applyFirst(CheapClass,['arg0','arg1']);
}
console.timeEnd('first Cheap');

console.time('second Cheap');
for(var i = 0; i < 10000; i++){
    test = applySecond(CheapClass,['arg0','arg1']);
}
console.timeEnd('second Cheap');

結果:

first Expensive: 76ms
second Expensive: 66ms
first Cheap: 52ms
second Cheap: 52ms
于 2010-10-25T23:22:18.650 に答える
7

これを実現するためにコンストラクターをチェーンできるという事実を利用できますがapply(...)、これにはプロキシクラスの作成が必要です。以下のconstruct()関数を使用すると、次のことができます。

var f1 = construct(Foo, [2, 3]);
// which is more or less equivalent to
var f2 = new Foo(2, 3);

construct()機能:

function construct(klass, args) {

  function F() {
    return klass.apply(this, arguments[0]); 
  }; 

  F.prototype = klass.prototype; 

  return new F(args);

}

それを使用するいくつかのサンプルコード:

function Foo(a, b) {
  this.a = a; this.b = b;
}

Foo.prototype.dump = function() {
  console.log("a = ", this.a);
  console.log("b = ", this.b);
};

var f = construct(Foo, [7, 9]);

f.dump();
于 2010-01-28T12:34:43.920 に答える
0

@CMSソリューションを完成させ、プロトタイプチェーンを保持するには、次のようにします。

var mid_parser = {};
mid_parser.__proto__ = Parser.prototype;
Parser.apply(mid_parser, mid_patterns);

ちなみに、IE8では動作しません。

于 2012-10-09T21:49:09.013 に答える