.apply() を 'new' 演算子と共に使用する。これは可能ですか? 質問する

.apply() を 'new' 演算子と共に使用する。これは可能ですか? 質問する

JavaScript で、オブジェクト インスタンス (演算子経由new) を作成し、コンストラクターに任意の数の引数を渡したいのですが。これは可能ですか?

私がやりたいことは次のようなものです (ただし、以下のコードは機能しません)。

function Something(){
    // init stuff
}
function createSomething(){
    return new Something.apply(null, arguments);
}
var s = createSomething(a,b,c); // 's' is an instance of Something

答え

ここでの回答から、オペレーター.apply()に電話をかける組み込みの方法は存在しないことが明らかになりましたnew。ただし、この問題に対して非常に興味深い解決策がいくつか提案されました。

私が好んだ解決策はこれはマシュー・クラムリーからのものだ(プロパティを渡すように変更しましたarguments):

var createSomething = (function() {
    function F(args) {
        return Something.apply(this, args);
    }
    F.prototype = Something.prototype;

    return function() {
        return new F(arguments);
    }
})();

ベストアンサー1

ECMAScript5のFunction.prototype.bind物事はかなりきれいになります:

function newCall(Cls) {
    return new (Function.prototype.bind.apply(Cls, arguments));
    // or even
    // return new (Cls.bind.apply(Cls, arguments));
    // if you know that Cls.bind has not been overwritten
}

以下のように使用できます。

var s = newCall(Something, a, b, c);

あるいは直接的にも:

var s = new (Function.prototype.bind.call(Something, null, a, b, c));

var s = new (Function.prototype.bind.apply(Something, [null, a, b, c]));

これと評価ベースのソリューション次のような特殊なコンストラクタを使用しても常に機能するのは、次のものだけですDate

var date = newCall(Date, 2012, 1);
console.log(date instanceof Date); // true

編集

少し説明します。new限られた数の引数を取る関数を実行する必要があります。bindメソッドを使用すると、次のように実行できます。

var f = Cls.bind(anything, arg1, arg2, ...);
result = new f();

キーワードはのコンテキストをリセットするので、パラメータanythingはあまり重要ではありません。ただし、構文上の理由から必要です。呼び出しについては、次のようにします。可変数の引数を渡す必要があるため、次のようにします。newfbind

var f = Cls.bind.apply(Cls, [anything, arg1, arg2, ...]);
result = new f();

これを関数でラップしてみましょう。Clsは引数 0 として渡されるので、 になりますanything

function newCall(Cls /*, arg1, arg2, ... */) {
    var f = Cls.bind.apply(Cls, arguments);
    return new f();
}

実際には、一時f変数はまったく必要ありません。

function newCall(Cls /*, arg1, arg2, ... */) {
    return new (Cls.bind.apply(Cls, arguments))();
}

bind最後に、それが本当に必要なものであることを確認する必要があります。 (Cls.bindは上書きされている可能性があります)。これを に置き換えるFunction.prototype.bindと、上記のような最終結果が得られます。

おすすめ記事