1. ホーム
  2. javascript

[解決済み] .apply() を 'new' 演算子で使用する。これは可能ですか?

2022-03-20 21:40:41

質問

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);
    }
})();

解決方法は?

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]));

これと evalベースのソリューション のような特殊なコンストラクタを使用しても、常に動作する唯一のものです。 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 パラメータはあまり重要ではありません。 new キーワードがリセットされ f のコンテキストを指定します。しかし、構文上の理由から、これは必要です。では bind を呼び出します。可変個数の引数を渡す必要があるので、これでうまくいく。

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 で、最終的に上記のような結果になります。