调用列表中的每个函数

时间:2013-04-10 10:21:47

标签: javascript functional-programming

我有一系列功能,正在寻找一种简洁的方法来按顺序调用每个功能。

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)

为什么后一个例子不起作用?

3 个答案:

答案 0 :(得分: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

但在您的第三个示例中,您通过call强制直接Function.call.prototype.call,但在这种情况下,f不再作为参数传递,这意味着您的{{1}将尝试调用Function.call.call,因此您获得undefined。当您将TypeError放入Function.call.call时,您传递map()作为参数。

callback将立即生效。 callFunction.call.callFunction.call.call()完全相同,只需在您使用第3个示例时立即进行评估。

答案 1 :(得分:4)

此简化代码表现出类似的问题:

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

在这种情况下,一旦Function.call.call被调用,它就不会记住它所源自的上下文(即Function.call)。要保存此上下文,您可以使用此 unholy构造技巧:

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(不推荐)来引用。

答案 2 :(得分: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);
})

现在显而易见的是invokerf一起调用为this。当它在内部尝试依次调用this时,会按预期调用函数。

现在看看:

fns.map(Function.call.call);

和等效表格

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

显而易见,此处,invoker被调用时thisundefined;因此它不能自己调用​​,这会产生TypeError