【发布时间】:2015-07-28 10:42:12
【问题描述】:
出于教育目的,我试图重新创建 Underscore.js 的 _.reduce() 方法。虽然我能够使用 for 循环以明确的方式做到这一点。但这远非理想,因为它会改变作为参数提供的原始列表,这是危险的。
我还意识到使用函数式编程风格创建这样的方法更难,因为不可能显式设置 i 值以进行循环。
// Explicit style
var reduce = function(list, iteratee, initial) {
if (Array.isArray(list)) {
var start;
if (arguments.length === 3) {
start = initial;
for (var i = 0; i < list.length; i++) {
start = iteratee(start, list[i], i);
}
} else {
start = list[0];
for (var i = 1; i < list.length; i++) {
start = iteratee(start, list[i], i);
}
}
}
if (list.constructor === Object) {
var start;
if (arguments.length === 3) {
start = initial;
for (var key in list) {
start = iteratee(start, list[key], key);
}
} else {
start = list[Object.keys(list)[0]];
// Delete the first property to avoid duplication.
delete list[Object.keys(list)[0]];
for (var key in list) {
start = iteratee(start, list[key], key);
}
}
}
return start;
};
让我苦恼的是,当我的 reduce() 提供了一个参数 initial 时,我需要随后跳过或删除参数的第一个 element 或 property 以用于将返回的最终值。因为不这样做会重复计算第一个元素/属性。在创建具有函数式编程风格的函数时,我想不出我怎么能做这样的事情,涉及_.each() 或forEach()。
这是我的 reduce() 的功能样式,它正在部分工作。提供memo(initial value) 时它可以正常工作,因为我不需要跳过第一个元素/属性。但是当没有提供 memo 时它不能正常工作,因为那时我将 memo 设置为第一个元素或属性,我应该能够在循环期间跳过它,我不知道如何。
// Functional style (not working without memo)
var reduce = function(list, iteratee, memo) {
var memo = memo || list[0] || list[Object.keys(list)[0]];
_.each(list, function(element, index, list){
memo = iteratee(memo, element, index, list);
});
return memo;
};
我花了很长时间在 Google 上搜索我的问题的答案。但是没能找到。我非常感谢您的建议。谢谢。
最后,这是我想出的一个附加代码,它不起作用,但我认为它应该。
var reduce = function(list, iteratee, memo) {
var collection = list;
var accumulation;
_.each(collection, function(item){
if (arguments.length < 3) {
if (Array.isArray(collection)) {
accumulation = collection[0];
collection.shift();
accumulation = iteratee(accumulation, item);
} else {
accumulation = collection[Object.keys(collection)[0]];
delete collection[Object.keys(collection)[0]];
accumulation = iteratee(accumulation, item);
}
} else {
accumulation = memo;
accumulation = iteratee(accumulation, item);
}
});
return accumulation;
};
【问题讨论】:
-
你可能不知道普通的旧 JavaScript already comes with reduce() for arrays,那么为什么不开始使用它而不是滚动大量
for循环呢? -
如果 OP 需要支持 IE 8,那么他们将无法访问
Array.prototype.reduce()。此外,OP 提到这是一项学术活动。 -
感谢迈克的意见。我知道原生数组方法
reduce()。我没有使用它,因为我想了解它是如何组成的,而且我想让它也支持一个 Object 作为它的列表参数。
标签: javascript functional-programming underscore.js reduce