我有一系列功能,正在寻找一种简洁的方法来按顺序调用每个功能。
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)
为什么后一个例子不起作用?
答案 0 :(得分:5)
for (var i = 0, len = fns.length; i < len; i++) {
fns[i].call();
};
这是工作fiddle。
使用上述Function.prototype.call
和Function.prototype.apply
来调用函数。使用call
和apply
,您可以将执行范围和arguments
传递给函数调用。如果您不需要,可以直接执行:
for (var i = 0, len = fns.length; i < len; i++) {
fns[i]();
};
关于您的代码:
Array.prototype.map
是一个需要callback
和scope 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
将立即生效。 call
与Function.call.call
或Function.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);
})
现在显而易见的是invoker
与f
一起调用为this
。当它在内部尝试依次调用this
时,会按预期调用函数。
现在看看:
fns.map(Function.call.call);
和等效表格
fns.map(function (f) {
var invoker = Function.call;
invoker.call();
})
显而易见,此处,invoker
被调用时this
为undefined
;因此它不能自己调用,这会产生TypeError
。