Javascript数组方法(如forEach
)具有thisArg
参数,该参数用作调用回调的上下文:
array.forEach(callback[, thisArg])
和every
,some
,filter
和map
一样。但是,reduce
和reduceRight
没有此类参数。这有什么特别的原因,或某些原因没有必要吗?
例如,考虑使用reduceRight
的以下功能组合实现:
function compose () {
var fns = [].slice.call(arguments,0);
return function result() {
return fns.reduceRight(
function (prev,cur){
return [cur.apply(this,prev)];
},
arguments
)[0];
};
}
我想使这个“知道”,所以正在调用的函数在调用compose
返回的函数的上下文中调用。目前,它们似乎是在全局对象的上下文中调用的。我可以在函数var self=this;
的顶部执行旧的result
,并将其用作cur.apply
调用的第一个参数,我当前有this
,但那样做如果reduce
采用thisArg
参数,则不必要。
我在这里遗漏了什么,有什么关于reduce
会使这不必要或无用吗?
更新
@kangax是的,发生在我身上。对我来说,批评API的设计远非如此,但reduce
的签名对我来说似乎有点奇怪。第二个可选参数的功能与普通的可选参数不同,后者通常只有一个默认值;相反,它的存在或不存在会改变行为,基本上会根据签名(参数计数)重载函数。当第二个参数不存在时,数组的第一个元素成为起始值,第一个对回调的调用是第二个值。在我看来,只需调用
array.slice(1).reduce(fn,array[0])
而不是为省略第二个参数的情况构建特殊规则,而这反过来,如果你的推定是正确的,那么也基本上不可能找出指定thisArg
参数的位置。再说一次,我确信这些问题在规范被删除时已经有争议,并且可能有充分的理由采用这种方法。
答案 0 :(得分:4)
两个可选参数变得混乱,因为reduce
(Right
)已经涵盖了两个功能(参见Wikipedia),这两个功能在纯语言中有区别(例如名为foldl
和Haskell中的foldl1
)。引用Brendan Eich:
所以这意味着reduce需要一个回调参数和两个可选参数:thisObject和init。哪一个应该先来?更常见的可能是init,但是你将回调arg与“thisObject”arg分开,这可能没问题。这样多个可选参数有点混乱......
或者,我们可以消除额外的“thisObject”参数,因为人们总是 [使用绑定] 。
我认为这不是一个大问题,因为这些功能性高阶函数主要用于 lamdba - 函数表达式(如在你的例子中)。当然有一点不一致,但我们可以忍受。想象一下:
array.reduce(callback[, initialValue[, thisArg]])
无法真正使用,我们无法真正确定“if an initialValue was provided”,因为这意味着arguments.length < 2
- 我们也可以从字面上传递undefined
。这意味着
array.reduce(callback[, thisArg[, initialValue]])
这很难看,因为如果我们只想要一个初始值,我们总是需要将null
或其他内容传递给thisArg
。
你注意到你已经在对Kangax的评论中(“第二个可选参数的功能与普通的可选参数不同,[...]它的存在或不存在会改变行为”),但我不能支持你的陈述
只需调用
即可轻松模拟此行为array.slice(1).reduce(fn,array[0])
因为a)不能使用复杂(链式)表达式而不是array
变量而b)是麻烦的。
答案 1 :(得分:3)
在Es-discuss邮件列表中,您可以在回答http://article.gmane.org/gmane.comp.lang.javascript.ecmascript4.general/4770
中找到使用回调的其他方法采用'thisArg'不是因为它 需要甚至有用,但为了兼容性,因为他们已经做到了 在提供这些功能的现有实现中。
答案 2 :(得分:3)
您始终可以使用此方法:
array.reduce(callback.bind(context), initialValue);
...以便将特定上下文附加到回调函数。