高阶函数 - Javascript

时间:2012-11-03 19:58:20

标签: javascript higher-order-functions

我正在通过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]);
}

2 个答案:

答案 0 :(得分:3)

  

我看到reduce正在传递匿名函数而不是组合函数

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

combine(base, element) vs function(total, element)

  

这两个函数调用基本上彼此相同:combine(base,element)和function(total,element)?

不,他们完全不同。

前者是函数调用,由combine引用的函数 然而,第二个评估为新的函数值。在以下情况下:

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

reduce()正在传递一个函数值,这意味着,新函数创建的,一个接受两个参数的函数(表示为totalelement)。然后将此函数传递给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

每个anon0testarray都会传递到函数中。在函数中,可以通过函数定义中的参数名访问它们的值。