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

3 回答 3

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

这是工作小提琴

如上所述使用Function.prototype.calland来调用函数。Function.prototype.apply使用callandapply您可以将执行范围传递arguments给函数调用。如果您不需要,您可以简单地执行以下操作:

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

关于您的代码:

Array.prototype.mapcallback是一个接受和的函数scope as parameters。在前两个示例中,您使用匿名函数作为callback并调用由 自动传递给它的参数Array.prototype.map。为了扩展,您的代码相当于:

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

所以上面说的完全正确。通过 using 遵循相同的原则Function.call.call,您正在调用f通过 map 作为参数传递的函数。

但是在您的第三个示例中,您强制使用直接callvia Function.call.prototype.call,但是在这种情况下,f不再作为参数传递,这意味着您Function.call.call将尝试调用undefined,因此您得到了TypeError. 当您放入 时Function.call.callmap()不会将 acallback作为参数传递。

call立即。与, 或Function.call.call完全相同,使用时会立即对它进行评估,就像您在第三个示例中所做的那样。Function.call.call()Function.call.call(undefined)

于 2013-04-10T10:23:30.573 回答
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)invoke也是如此alert.call(window)callFn理解这种行为在作为回调的一部分被调用的情况下很重要,例如Array.forEach在每次迭代中传递三个参数。

fns.forEach(callFn);

在您的情况下,里面的任何函数fns都没有使用传递的参数,但在幕后它们被这样调用:

fns[0].call(0, fns)

Sothis等于元素的索引(即Number(0))并arguments[0]等于函数数组。敏锐的观察者可能已经注意到元素的值落在裂缝之间,尽管它仍然可以使用arguments[0][this]arguments.callee(不推荐)来引用。

于 2013-04-10T10:48:26.287 回答
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);
})

现在很明显,它是用asinvoker调用的。当它在内部尝试依次调用时,会按预期调用您的函数。fthisthis

现在看看这个:

fns.map(Function.call.call);

和等价形式

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

应该很明显,这里,when invokeris invoked thisis undefined; 因此它本身不能被调用,这会产生TypeError.

于 2013-04-10T10:41:39.963 回答