我正在通过Eloquent Javascript工作。函数 count 将数组和测试函数(等于(x))作为参数,并返回测试函数返回true的数组中的元素数量。
我理解这些函数的广泛使用方式,从逻辑上讲,传递给reduce的匿名函数的 total 参数的值为零。
有人可以帮我看一下具体的价值来自哪里?我希望在脑海里有一个更清晰的画面。
function count(test, array) {
return reduce(function(total, element) { // Where is the value for total coming from?
return total + (test(element) ? 1 : 0);
}, 0, array);
}
function equals(x) {
return function(element) {return x === element;};
}
function countZeroes(array) {
return count(equals(0), array);
}
从早先减少功能:
function reduce(combine, base, array) {
forEach(array, function (element) {
base = combine(base, element);
});
return base;
}
forEach早期功能:
function forEach(array, action) {
for (var i = 0; i < array.length; i++)
action(array[i]);
}
答案 0 :(得分:3)
我看到reduce正在传递匿名函数而不是组合函数
这不是真的。匿名函数是 combine
函数。
combine(base, element)
vs function(total, element)
这两个函数调用基本上彼此相同:combine(base,element)和function(total,element)?
不,他们完全不同。
前者是函数调用,由combine
引用的函数
然而,第二个评估为新的函数值。在以下情况下:
reduce(function(total, element) {...}, ...);
reduce()
正在传递一个函数值,这意味着,新函数是创建的,一个接受两个参数的函数(表示为total
和element
)。然后将此函数传递给reduce
。
让我从昨天开始回收我的可视化。重要的是要意识到,这不仅适用于您的案例,而且它适用于 reduce(左)概念的每个实施例
return value of reduce()
/
etc ...
/
combine
/ \
combine xs[2]
/ \
combine xs[1]
/ \
0 xs[0]
当然,这只会显示发生了什么,而不是 ,我认为在您的情况下,您需要如何 。只需记住这种可视化,看看结果将会发生什么。
为了更清楚地说明发生了什么,我将逐步替换正在传递的功能。
开始该计划:
function countZeroes(array) {
return count(equals(0), array);
}
equals(0)
(你可以称之为currying形式)求值为一个函数,传递给count()
。
这基本上导致了以下count()
函数:
function count(array) {
return reduce(function(total, element) { // Where is the value for total coming from?
return total + (0 == element ? 1 : 0);
}, 0, array);
}
从这里,我们可以提取combine
参数:
function combine(total, element) { // Where is the value for total coming from?
return total + (0 == element ? 1 : 0);
}
这是在reduce函数中使用的函数:
function reduce(base = 0, array) {
forEach(array, function (element) {
base = combine(base, element);
});
return base;
}
从reduce(0, array)
函数调用 count()
。现在可以像这样重写传递给forEach
的函数,并考虑我们combine
的帐户实现:
function reduce(base = 0, array) {
forEach(array, function (element) {
base = base + (0 == element ? 1 : 0);
});
return base;
}
请注意,base
代表我们的total
。
作为最后一步,我们会考虑forEach()
的作用。
function reduce(base = 0, array) {
for (var i = 0; i < array.length; i++)
base = base + (0 == array[i] ? 1 : 0);
}
return base;
}
所以这就是count()
基本上看起来的样子,所有的调用都被解开了:
function count(array) {
var base = 0;
for (var i = 0; i < array.length; i++)
base = base + (0 == array[i] ? 1 : 0);
}
return base;
}
答案 1 :(得分:2)
您传递给reduce的3个参数是:
{
combine:function(total, element){...},
base:0,
array:array
}
然后该函数接受base
并将其作为combine
参数传递给total
函数:
base = combine(base, element);
基本上,这里发生的是对于刚刚传递的数组中的每个元素(作为第三个参数array
),该函数接受参数base
并使用您拥有的匿名函数递增它提供(首先检查元素是否通过test
)。最后,在迭代了所有元素之后,它返回最终值base
。
也许这有助于解释:
function count(test, testarray) {
var anon = function(total, element) { // Where is the value for total coming from?
return total + (test(element) ? 1 : 0);
};
//now anon is a function.
return reduce(anon, 0, testarray);
}
让我们仔细看看函数调用和定义:
return reduce(anon , 0 , testarray);
| | |
v v v
function reduce(combine, base, array) {
combine; //the function that is passed in as the first argument
base; //the number that is passed in as the second argument
array; //the array that is passed in as the third argument
每个anon
,0
和testarray
的值都会传递到函数中。在函数中,可以通过函数定义中的参数名访问它们的值。