Javascript数组方法,例如forEach有一个thisArg参数,用作调用回调的上下文:
array.forEach(callback[, thisArg])
Run Code Online (Sandbox Code Playgroud)
因为这样做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];
};
}
Run Code Online (Sandbox Code Playgroud)
我想使这个"知道",所以正在编写的函数compose在调用返回函数的上下文中被调用.目前,它们似乎是在全局对象的上下文中调用的.我可以var self=this;在函数的顶部执行旧的操作result,并将其用作cur.apply调用的第一个参数,我目前拥有this,但如果reduce采用thisArg参数则不需要.
我在这里遗漏了什么,有什么东西reduce可以使这不必要或无用吗?
UPDATE
@kangax是的,发生在我身上.对我来说,批评API的设计远非如此,但签名reduce似乎对我来说有点奇怪.第二个可选参数的功能与普通的可选参数不同,后者通常只有一个默认值; 相反,它的存在或不存在会改变行为,基本上会根据签名(参数计数)重载函数.当第二个参数不存在时,数组的第一个元素成为起始值,第一个对回调的调用是第二个值.在我看来,这种行为可以通过简单的调用轻松模拟
array.slice(1).reduce(fn,array[0])
Run Code Online (Sandbox Code Playgroud)
而不是为省略第二个参数的情况建立特殊规则,反过来,如果你的推定是正确的,也基本上不可能弄清楚在哪里指定thisArg参数.再说一次,我确信这些问题在规范被删除时已经有争议,这种方法可能有充分的理由.
您可以随时使用此方法:
array.reduce(callback.bind(context), initialValue);
Run Code Online (Sandbox Code Playgroud)
...为了将特定上下文附加到回调函数。
两个可选参数会让它变得混乱,因为reduce( Right) 已经涵盖了两个功能(参见维基百科),这两个功能在纯语言中是有区别的(例如,namedfoldl和foldl1Haskell)。引用布伦丹·艾奇的话话:
\n\n\n所以这意味着reduce需要一个回调参数和两个可选参数:thisObject和init。哪一个应该放在第一位?更常见的可能是 init,但是随后您将回调参数与“thisObject”参数分开,这也许没问题。多个可选参数这样有点混乱......
\n\n或者,我们可以消除额外的“thisObject”参数,因为人们总是可以[使用绑定]。
\n
我不认为这是一个大问题,因为这些功能性高阶函数主要与lamdba一起使用-函数表达式一起使用(就像在您的示例中一样)。当然,会有一点不一致,但我们可以忍受。想象一下替代方案:
array.reduce(callback[, initialValue[, thisArg]])\nRun Code Online (Sandbox Code Playgroud)\n\n无法真正使用,我们无法真正确定“是否提供了初始值”,因为这意味着arguments.length < 2- 我们可以通过undefined也可以按字面意思传递。所以这意味着
array.reduce(callback[, thisArg[, initialValue]])\nRun Code Online (Sandbox Code Playgroud)\n\n这很丑陋,因为我们总是需要经过null或做一些事情thisArg。
您注意到在对 Kangax 的评论中(“第二个可选参数的功能与普通可选参数不同,[\xe2\x80\xa6] 它的存在或不存在会改变行为”),但我不能支持你的声明
\n\n\n\n\n只需调用即可轻松模拟此行为
\narray.slice(1).reduce(fn,array[0])
因为这将 a) 不适用于复杂的(链式)表达式而不是array并且 b) 很麻烦。