javascript - 自定义 reduce 函数实现 - 为什么要传递这个特定的参数列表?
问题描述
我发现这个超级有用的要点。在 reduce 函数实现中,传递了一长串参数:undefined, accumulator, this[i], this, i
. 我不明白为什么。据我了解,该行应该是accumulator = callback.call(accumulator, this[i])
. 但是,如果我删除任何这些参数,reduce 函数将无法正常工作。请帮助我填补我的理解空白!
Array.prototype.myReduce = function(callback, initialVal) {
var accumulator = (initialVal === undefined) ? undefined : initialVal;
for (var i = 0; i < this.length; i++) {
if (accumulator !== undefined)
accumulator = callback.call(undefined, accumulator, this[i], i, this);
else
accumulator = this[i];
}
return accumulator;
};
//tests
var numbers3 = [20, 20, 2, 3];
var total = numbers3.myReduce(function(a, b) {
return a + b;
}, 10);
console.log(total); // 55
var flattened = [
[0, 1],
[2, 3],
[4, 5]
].reduce(function(a, b) {
return a.concat(b);
});
console.log(flattened); //[ 0, 1, 2, 3, 4, 5 ]
解决方案
第一个参数call
是this
要在回调中使用的值。但是这个实现在回调内部没有使用任何this
东西,所以第一个参数必须是undefined
. 如果你这样做
accumulator = callback.call(accumulator, this[i]).
然后你callback
用一个参数调用 the this[i]
(this
回调内部的位置将是accumulator
,这绝对不是你想要的)。
也就是说,要点中的实现是不正确的——当最后一个回调返回时,它没有调用回调undefined
。它也没有正确检查初始值(可能已作为参数传递,但 is undefined
):
// Unaltered function below:
Array.prototype.myReduce = function(callback, initialVal) {
var accumulator = (initialVal === undefined) ? undefined : initialVal;
for (var i = 0; i < this.length; i++) {
if (accumulator !== undefined)
accumulator = callback.call(undefined, accumulator, this[i], i, this);
else
accumulator = this[i];
}
return accumulator;
};
// My test:
[1, 2, 3].reduce((a, b, i) => {
console.log('native reduce iteration!');
return i === 0 ? b : undefined;
}, 0);
[1, 2, 3].myReduce((a, b, i) => {
console.log('CUSTOM reduce iteration!');
return i === 0 ? b : undefined;
}, 0);
要修复它,请无条件调用回调(如果在没有初始值的空数组上调用,请记住抛出错误):
// Unaltered function below:
Array.prototype.myReduce = function(...args) {
const [callback, initialVal] = args;
let i;
let accumulator;
if (args.length >= 2) {
accumulator = initialVal;
i = 0;
} else if (this.length === 0) {
throw new TypeError('Reduce called on an empty array with no initial value');
} else {
accumulator = this[0];
i = 1;
}
for (; i < this.length; i++) {
accumulator = callback.call(undefined, accumulator, this[i], i, this);
}
return accumulator;
};
// My test:
[1, 2, 3].reduce((a, b, i) => {
console.log('native reduce iteration!');
return i === 0 ? b : undefined;
}, 0);
[1, 2, 3].myReduce((a, b, i) => {
console.log('CUSTOM reduce iteration!');
return i === 0 ? b : undefined;
}, 0);
console.log(
[2, 3, 4].myReduce((a, b) => a + b)
);
推荐阅读
- android - 如何从 rxjava 平面图中调用协程用例
- python - 为什么 torchvision.utils.make_grid() 返回所需网格的副本?
- c++ - 出现此错误时我该怎么办:“int”类型的参数与 C++ 中“int(*)[101]”类型的参数不兼容
- sql - 触发以更新没有记录的值
- python - 如何使用 SerializerMethodField 订购查询集?
- javascript - 如何在Javascript中将对象数组转换为单个对象
- arrays - 如何在 vb.net 上反序列化这个 json?
- java - python中的LinkedHashSet替代方案
- sql - “引用表中没有主键或候选键”,我没有看到什么?
- google-cloud-dataflow - KafkaIO 检查点持久性与 Google Dataflow Runner