2013-04-10 4 views
8

私は関数の配列を持っており、それぞれを順番に呼び出す簡潔な方法を探しています。リスト内の各関数を呼び出す

fns = [ 
    function a() { console.log('a') }, 
    function b() { console.log('b') }, 
    function c() { console.log('c') }, 
] 

この作品:

fns.map(function (f) { f() }) 

ので、これはありませんが:

fns.map(function (f) { Function.call.call(f) }) 

しかし、これはTypeError例外を発生させます:

fns.map(Function.call.call) 

はなぜ後者の例の仕事はしていません?

答えて

4

この簡略化されたコードは、同様の問題を示す:ここで

var x = Function.call.call; 
x(alert); 

を、一度Function.call.callが呼び出され、それが由来する文脈(すなわちFunction.call)を覚えていないであろう。

Function.call.bind(Function.call) 

それはFunction.callの状況がこのようにコンテキストを保存し、それ自体にバインドされていることにより、新しい関数を返します。このコンテキストを保存するには、この 不浄構造 トリックを使用することができます。あなたは新しい変数にこの式を保存することができます。

var callFn = Function.call.bind(Function.call); 

さて、callFn(alert)alert.call()と同じです。追加の引数はそのまま渡されるので、callFn(alert, window)alert.call(window)を呼び出します。この動作を理解することは、Array.forEachなどのコールバックの一部としてcallFnが呼び出され、各繰り返しで3つの引数が渡される状況では重要です。あなたのケースでは

fns.forEach(callFn); 

fns内部の機能はどれも渡される引数を使用していないが、舞台裏で、彼らはこのように呼ばれている:だから thisは、要素のインデックスを(等しい

fns[0].call(0, fns) 

すなわちNumber(0))、arguments[0]は関数の配列と等しくなります。鋭い観察者は、要素の値が亀裂の間にあることに気付いたことがあるかもしれませんが、まだarguments[0][this]、あるいはarguments.callee(廃止予定)を使用して参照されている可能性があります。

+0

ビンゴ、それだけです!どうもありがとう。 – georg

+0

引数についてのフォローアップは良好ですが、なぜ呼び出されるのですか?単純に '引数[0] [this]'に何が問題なのですか? – georg

+0

@ thg435これは良い点です。それはこのケースではうまくいくでしょう:)ありがとう! –

5
for (var i = 0, len = fns.length; i < len; i++) { 
    fns[i].call(); 
}; 

ここでは、作業fiddleです。

上記のようにFunction.prototype.callFunction.prototype.applyを使用して関数を呼び出します。 callapplyでは、実行スコープとargumentsを関数呼び出しに渡すことができます。あなたがそれを必要としない場合は、単に行うことができます。

for (var i = 0, len = fns.length; i < len; i++) { 
     fns[i](); 
}; 

をあなたのコードについて:

Array.prototype.mapcallbackscope as parametersをとる関数です。最初の2つの例では、無名関数をcallbackとして使用していて、パラメータには自動的にArray.prototype.mapによって渡されたパラメータが呼び出されます。展開するには、コードは次のようになります。

function single(element) { 
    element(); 
}; 
fns.map(single); 

したがって、上記は完全に正しいです。 Function.call.callを使用して同じ原則に従って、関数fをmapでパラメータとして渡しています。

しかし、あなたの第三の例では、あなたがFunction.call.prototype.call経由で直接callを余儀なくされているが、しかし、この場合には、fは、もはやあなたのFunction.call.callはあなたがTypeErrorを得るため、undefinedを呼び出そうとすることを意味し、パラメータとして渡されていないされます。 Function.call.callmap()に入れると、ではなく、で、callbackを引数として渡します。

callはすぐになります。 Function.call.callは、Function.call.call()、またはFunction.call.call(undefined)と全く同じものです。これは、3番目の例のように使用するとすぐに評価されます。

+3

OPはおそらくこれをすべて知っている可能性が高いです。質問は*どうして*どうやって*どうやっているのかを尋ねます。 – Jon

+0

私はその間に同じことを実際に書いていました! +1 – Jon

3

TypeErrorFunction.prototype.callが内部的にthis(指定されたコンテキストとパラメータを使用しますが、ディスカッションでは重要ではありません)を呼び出すために発生します。

はのは、invokerthisとしてfで呼び出されることになりまし明白である同等

fns.map(function (f) { 
    var invoker = Function.call; 
    invoker.call(f); 
}) 

として働い

fns.map(function (f) { Function.call.call(f) }) 

を書き換えてみましょう。内部的にthisを呼び出すと、関数が呼び出されます。

は今、これを見て:

fns.map(Function.call.call); 

と同等のフォーム

fns.map(function (f) { 
    var invoker = Function.call; 
    invoker.call(); 
}) 

invokerが呼び出されたときに、ここで、thisundefinedであることは言うまでもないです。したがって、それ自身を呼び出すことはできず、これによってTypeErrorが発生します。

関連する問題