3

のような引数のリストがあり、のvar args = ['blah', 1, 3.9]ように新しくする必要があるものに適用したいと思いますnew bleh.Thinggy(a, b, c)

次のことをしたいvar m = {}; bleh.Thinggy.apply(m, args);

私が考えていないことがあるのではないかと心配しています。これが安全かどうか誰かが知っていますか?

4

2 に答える 2

3

プロトタイプの継承が期待どおりに機能しないため、現在の方法に欠陥があります。コンストラクターに
相当するものは次のとおりです。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 Imagenew 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
于 2012-10-10T19:50:38.650 に答える
0

適用は安全ですが、のインスタンスは返されません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
于 2012-10-10T19:49:35.850 に答える