[解決済み] .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);
}
})();
解決方法は?
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
で、最終的に上記のような結果になります。
関連
-
Vueがechartsのtooltipにクリックイベントを追加するケーススタディ
-
Vueの要素ツリーコントロールに破線を追加する説明
-
vueにおけるv-forループオブジェクトのプロパティ
-
vueのプロジェクトでモックを使用する方法を知っていますか?
-
Vueのフォームイベントのデータバインディングの説明
-
[解決済み] どのような場合に '$this' よりも 'self' を使うべきですか?
-
[解決済み] 新しい配列を作成せずに、既存のJavaScript配列を別の配列で拡張する方法
-
[解決済み] 型名の後の括弧は、newで違いがあるのでしょうか?
-
[解決済み] コンストラクタ関数が Promise を返すのは悪い習慣ですか?
-
[解決済み] デコレーター」とは何ですか、どのように使うのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
JavaScriptの関数この指摘の問題を説明
-
Vue Element-uiは、アイコンを追加するためのツリーコントロールノードを詳細に実装しています。
-
JavaScriptにおけるマクロタスクとミクロタスクの詳細
-
vueの補間表現とv-textディレクティブの違いについて
-
vueにおけるfilterの適用シーンについて解説します。
-
Vueのフォームイベントのデータバインディングの説明
-
[解決済み】最大呼び出しスタックサイズ超過エラー
-
[解決済み】JavaScriptの配列でforEachが関数でない不具合
-
[解決済み】ERROR エラーです。スイッチのname属性が指定されていないフォームコントロールの値アクセッサがない
-
Uncaught TypeError: null のプロパティ 'offsetHeight' を読み取れませんでした。