在 JavaScript 中原生实现 reduceRight 是错误的
Native implementation of reduceRight in JavaScript is wrong
对于数组a
元素f
的关联操作,以下关系应成立:a.reduce(f)
应等效于a.reduceRight(f)
。
事实上,它确实适用于关联和交换的操作。为例:
const a = [0,1,2,3,4,5,6,7,8,9];
const add = (a, b) => a + b;
console.log(a.reduce(add));
console.log(a.reduceRight(add));
但是,对于关联但不可交换的操作,它并不成立。例如:
const a = [[0,1],[2,3],[4,5],[6,7],[8,9]];
const concat = (a, b) => a.concat(b);
console.log(JSON.stringify(a.reduce(concat)));
console.log(JSON.stringify(a.reduceRight(concat)));
我们需要翻转f
的参数,以reduceRight
使它们等价:
const a = [[0,1],[2,3],[4,5],[6,7],[8,9]];
const concat = (a, b) => a.concat(b);
const concatRight = (b, a) => a.concat(b);
console.log(JSON.stringify(a.reduce(concat)));
console.log(JSON.stringify(a.reduceRight(concatRight)));
这让我相信reduceRight
的原生实现是错误的。
我认为reduceRight
功能应该按如下方式实现:
var REDUCE_ERROR = "Reduce of empty array with no initial value";
Array.prototype.reduceRight = function (f, acc) {
let { length } = this;
const noAcc = arguments.length < 2;
if (noAcc && length === 0) throw new TypeError(REDUCE_ERROR);
let result = noAcc ? this[--length] : acc;
while (length > 0) result = f(this[--length], result, length, this);
return result;
};
由于result
表示前一个值(右侧值(,因此将其作为函数f
的第二个参数是有意义的。当前值表示左侧值。因此,将当前值作为函数的第一个参数是有意义的 f
。这样,即使对于非交换结合运算,上述关系也成立。
所以,我的问题是:
- 按照
- 我的方式实施
reduceRight
不是更有意义吗? - 为什么本机
reduceRight
没有像我那样实现?
按照我的方式实施
reduceRight
不是更有意义吗?
或。但是,JavaScript 数组迭代器并非来自纯函数式编程背景。
为什么本机
reduceRight
没有像我那样实现?
因为具有相同的参数顺序更简单(更容易记住(,所以累加器始终排在第一位。
数组的原始操作是 reduce
,它一如既往地从 0 迭代到 n-1。只有在 Haskell 及其递归构建的列表中foldr
更有意义(具有build
对偶性,在无限列表上懒惰地工作......请注意命名不是reduce
+ reduceLeft
...
然后reduceRight
不会反转折叠操作,它只是反转迭代顺序。这也是文档和教程中通常如何解释的,例如在权威指南中:
reduceRight()
的工作方式与reduce()
一样,只是它从最高处处理数组。
此外,在 Mozilla 的 JS 1.8 数组附加功能中 reduce
/reduceRight
(参见错误 363040(的第一个实现遵循了这种方法:它只是翻转了 end 的开头并否定了步长值。
戴夫·赫尔曼(Dave Herman(对ES4规范的注释遵循了这一思路。它确实提到了 Haskell,但整个文档根本没有处理callback
的参数顺序。也许在 Haskells 不常见的语法或规范类型名称中丢失了不同的顺序,因此两个签名都以 (a -> b -> …
开头。对缺少的thisObject
参数进行了更多讨论。
一些相关摘录:
[该方法]的好处:
- 就像 Python => Python 社区的思想份额
- 折叠的完全通用性(左(
- 但也要做一个简单的情况,其中第一个元素是基础 元素,更简单
我猜大多数人会发现从左到右版本的减少更多
直观,因为它们通常从左到右迭代数组。 另外,这就是Python所做的。我认为提供一个reduceRight也很重要,
因为不是每个操作都是关联的,有时人们需要 从右到左。
最后,这就是进入 EcmaScript 规范的内容:
阵列附加功能 :按照FF当前支持的方式进行规范
- Node.js v6.2.0类扩展不是函数错误
- Jquery菜单操作不稳定,定位不正确,存在一般错误
- document.open/document.write没有正确地清除chrome中的文档——这是chrome的错误吗
- 试图在引导模式内动态生成图表,得到offsetWidth错误
- 为什么会出现错误;未捕获的类型错误:undefined不是函数;
- 我如何修复包含在captcha的addthis中的错误
- 同样,同样的错误'ahorcado.js:26未捕获类型错误:无法读取属性'beginPath'
- 节点是否需要模块传递带有方括号的arg?这是个错误吗
- Webpack/Rect:遵循egghead.io教程,但出现错误:您可能需要一个合适的加载程序来处理此文件类型
- CKFinder 3为所选文件返回错误的URL
- 同位素库错误:未捕获错误无布局模式包装生产线8
- 铬:“;未捕获的语法错误:意外的标记:"
- 如何通过自己获得Chrome扩展的用户反馈/错误报告
- 相位器状态未捕获参考错误
- /undefined在我的404错误日志中多次出现
- Javascript未捕获语法错误意外的标识符错误
- javascript:如何在antlr生成的Lexer中进行错误处理
- Angularjs工厂注入错误
- 可以设置“;文件名"发生错误时显示的内联脚本标记的
- 在 JavaScript 中原生实现 reduceRight 是错误的