2

我正在使用 Eloquent Javascript。函数count以一个数组和一个测试函数 ( equals(x) ) 作为参数,并返回数组中测试函数返回 true 的元素数量。

我理解这些函数工作的广泛方式,并且从逻辑上讲,传递给 reduce 的匿名函数的总参数的值为零。

有人可以帮我看看总价值的具体来源吗?我想在脑海中有一个更清晰的画面。

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]);
}
4

2 回答 2

3

我看到 reduce 被传递了一个匿名函数而不是 combine 函数

这不是真的。匿名函数就是combine函数。

combine(base, element)对比function(total, element)

这两个函数调用本质上是相等的:combine(base,element) 和 function(total,element)?

不,它们是完全不同的东西。

前者是函数调用,对 . 引用的函数进行调用combine
然而,第二个计算为一个新的函数值。如果是:

reduce(function(total, element) {...}, ...);

reduce()正在传递一个函数值,这意味着创建了一个新函数,该函数接受两个参数(用and表示)。然后将此函数传递给.totalelementreduce


让我从昨天开始回收我的可视化。重要的是要意识到,这不仅适用于您的案例,而且适用于reduce(left)概念的每个实施例。

                   return value of reduce()
                   /
                 etc ...
                /
            combine    
           /       \
       combine      xs[2]
      /       \
  combine      xs[1]
 /       \
0         xs[0]

当然,这仅显示发生了什么,而不是如何,我认为在您的情况下您要询问how。只要记住这个可视化,看看结果会发生什么。

替换函数

为了更清楚地说明发生了什么,我将逐步替换正在传递的函数。

程序开始:

function countZeroes(array) {
  return count(equals(0), array);
}

equals(0)(你可以称之为柯里化的一种形式)计算一个函数,该函数被传递给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;
}
于 2012-11-03T20:45:27.350 回答
2

您传递给 reduce 的 3 个参数是:

{
    combine:function(total, element){...},
    base:0,
    array:array
}

然后该函数将其作为参数base传递给函数:combinetotal

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

、和中的每一个的都被传递到函数中。在函数内,它们的值可以通过函数定义中的参数名称访问。anon0testarray

于 2012-11-03T20:07:33.817 回答