のような引数のリストがあり、のvar args = ['blah', 1, 3.9]
ように新しくする必要があるものに適用したいと思いますnew bleh.Thinggy(a, b, c)
。
次のことをしたいvar m = {}; bleh.Thinggy.apply(m, args);
私が考えていないことがあるのではないかと心配しています。これが安全かどうか誰かが知っていますか?
のような引数のリストがあり、のvar args = ['blah', 1, 3.9]
ように新しくする必要があるものに適用したいと思いますnew bleh.Thinggy(a, b, c)
。
次のことをしたいvar m = {}; bleh.Thinggy.apply(m, args);
私が考えていないことがあるのではないかと心配しています。これが安全かどうか誰かが知っていますか?
プロトタイプの継承が期待どおりに機能しないため、現在の方法に欠陥があります。コンストラクターに
相当するものは次のとおりです。method.apply(context, args)
// Given a list of arguments `args`:
var bindArgs = [Constructor.prototype].concat(args);
new (Function.prototype.bind.apply(Constructor, bindArgs));
Function.prototype.bind
およびの役割はFunction.prototype.apply
、対応するドキュメントで説明されています。注意:.bind
関数を返します!
簡単にする.bind
ために、固定数、たとえば2つの引数の使用方法を説明します。次に、以下は同じ効果があります。
Math.max.apply(Math, 2, 3);
Math.max.bind(Math, 2, 3)();
と
Math.max.apply(Math, 2, 3, 4, 5);
Math.max.bind(Math, 2, 3)(4, 5);
ドキュメントを見ただけでも、最初のフォームを確実に理解できます。ただし、2番目の形式は扱いにくいです。この場合、の引数の位置は関係ないため、これは機能しMath.max
ます。すべての引数の最大値が考慮され、すべての引数が同じように扱われます。
次に、カスタム関数を使用した例を示します。
function echoMe(name, age) {
console.log('Hello ' + name + '. Your age is ' + age);
console.log('this is ', this);
}
echoMe('Rob', '19');
// "Hello Rob. Your age is 19"
// "this is [object DOMWindow]" (non-strict mode)
var echoYou = echoMe.bind(null, "Oops");
echoYou("Peter", "19");
// "Hello Oops. Your age is Peter"
// "this is null"
この場合、引数の位置が重要であるため、最後の例は奇妙なことを示しています。実際、最初の引数はメソッドによって「おっと」にバインドさ.bind
れています。バインドされた関数 に渡された引数はechoYou
、引数リストに追加されます。さらに、コンテキストthis
がに変更されていることに気付きますnull
。
興味深い..以下を使用してコンテキストを変更してみましょう.apply
:
function printThisFood() {
console.log("this.food is " + this.food);
}
printThisFood.apply({food: "Fish"});
// "this.food is fish"
var locked = printThisFood.bind({food: "Strong"});
locked.apply({food: "Weak"});
// "This.food is Strong"
ご覧のとおり、!this.food
を介して定義されたコンテキストからのメソッドを引き続き指します。.bind
したがって、関数のコンテキストをロックする方法と、任意の数の固定引数を関数に渡す方法を知っています。これはコンストラクターに適用でき、答えの上に提示した関数になります。期待どおりに機能することを確認するには:
function Constructor() {
console.log(this instanceof Constructor); // true
console.log(this, arguments); // Convince yourself via console
}
var bindArgs = [Constructor.prototype].concat([1, 2]);
// is equal to [Constructor.prototype, 1, 2]
var BoundConstructor = Function.prototype.bind.apply(Constructor, bindArgs);
var instance = new BoundConstructor();
// Eliminated intermediate variable, and put on one line
var instance = new (Function.prototype.bind.apply(Constructor, bindArgs));
注:()
コンストラクターは括弧なしで初期化できるため、ワンライナーの括弧は省略しました。new Image
とnew Image()
同じように動作しています。
構築されたメソッドからプロパティをすぐに読み取る(またはメソッドを呼び出す)には、式全体を括弧で囲むか、追加()
してあいまいさを取り除くことができます。
(new (Function.prototype.bind.apply(Constructor, bindArgs))).method()
new (Function.prototype.bind.apply(Constructor, bindArgs))().method();
注2:引数リストに追加の引数が追加されることは引き続き保持されます。このプロパティは、特定のコンストラクターの最初の引数を「プリセット」するためにも使用できます。
function Stupid(obvious1, obvious2, foo) { this.interesting = foo; }
Stupid.prototype.onlymethod = function() { return this.interesting};
var saveKeyStroke = Function.prototype.bind.call(Stupid, Stupid.prototype, 1, 2);
// Or, equivalent:
//var saveKeyStroke=Function.prototype.bind.apply(Stupid,[Stupid.prototype,1,2]);
new saveKeyStroke('Fourth argument').onlymethod(); // "Fourth argument"
new saveKeyStroke().onlymethod(); // undefined
(new saveKeyStroke).onlymethod(); // undefined
適用は安全ですが、のインスタンスは返されませんbleh.Thinggy
。のインスタンスが必要な場合はbleh.Thinggy
、bleh.Thinggy.applyを使用する前にインスタンスを作成する必要があります。
コード:
var m = new bleh.Thinggy; // m is instance of bleh.Thinggy.
bleh.Thinggy.apply(m, args);
... use m as instance of bleh.Thinggy.apply