2013-04-10 44 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) }) 

然而,這引起了類型錯誤:

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)。在callFn被作爲回調的一部分調用時(例如Array.forEach),在每次迭代中傳遞三個參數的情況下,理解此行爲很重要。

fns.forEach(callFn); 

在你的情況下,沒有內部fns功能使用所傳遞的參數,但是在幕後,他們是所謂這樣的:

fns[0].call(0, fns) 

所以this等於元素的索引(即Number(0))和arguments[0]等於函數的數組。敏銳的觀察者可能已經注意到元素的值落在裂紋之間,儘管它仍然可以使用arguments[0][this]或者arguments.callee(不建議使用)引用。

+0

賓果,就是這樣!非常感謝。 – georg 2013-04-10 10:55:48

+0

關於參數的良好後續行動,但爲什麼'被調用者'?簡單地說'arguments [0] [this]'有什麼問題? – georg 2013-04-11 08:08:19

+0

@ thg435這是一個好點;這將在這種情況下工作:)更新,謝謝! – 2013-04-11 08:12:36

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.map是一個函數,callbackscope as parameters。在前兩個示例中,您使用的匿名函數爲callback,您可以通過Array.prototype.map自動調用傳遞給它的參數。要展開,您的代碼與此相當:

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

因此上述內容完全正確。按照使用Function.call.call的相同原則,您正在調用通過map作爲參數傳遞的函數f

但在你的第三個例子中,你正在迫使通過Function.call.prototype.call直接call,但是在這種情況下,f不再被作爲一個參數,這意味着你的Function.call.call將嘗試呼叫undefined,所以你得到的TypeError通過。當您將Function.call.call放入map()的內部時,您是而不是callback作爲參數。

call將立即。 Function.call.callFunction.call.call()Function.call.call(undefined)完全相同,如果您在第三個示例中使用,將立即對其進行評估。

+3

OP最有可能已經知道這一切。問題問*爲什麼*,而不是*如何*。 – Jon 2013-04-10 10:26:10

+0

其實我在寫這篇文章的時候也是一樣! +1 – Jon 2013-04-10 10:42:46

3

TypeError發生是因爲Function.prototype.call內部調用this(具有給定的上下文和參數,但這在討論中不重要)。

讓我們重寫工作

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

爲等效

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

這是現在很明顯,invoker被調用,fthis。如果內部試圖調用this,則按照預期調用函數。

現在看看這個:

fns.map(Function.call.call); 

和等價形式

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

這應該是顯而易見的,在這裏,當invoker調用thisundefined;因此它不能被自己調用,並且這引起TypeError

相關問題