为了账号安全,请及时绑定邮箱和手机立即绑定

reduce 内部的累加器函数由 Javascript 中的函数使用闭包进行包装

reduce 内部的累加器函数由 Javascript 中的函数使用闭包进行包装

叮当猫咪 2022-08-18 10:01:43
var arr = [{ name: "John", score: "8.8" }, { name: "John", score: "8.6" }, { name: "John", score: "9.0" }, { name: "John", score: "8.3" }, { name: "Tom", score: "7.9" }],    avgScore = arr.reduce(function (sum, count) {        return function (avg, person) {            if (person.name === "John") {                sum += +person.score;                return sum / ++count;            }            return avg;        };    }(0, 0), 0);console.log(avgScore);我发现了这个有趣的代码,我想知道闭包在Javascript中是如何工作的。令我吃惊的是,带有累加器和迭代元素的函数被另一个函数包装。reduce不应该接受带有累加器和迭代元素的函数,那么为什么reduce函数仍然有效,尽管具有vave迭代元素的累加器函数被另一个函数包装?另外,为什么我们使用(0,0)调用带有闭包的函数,但是在第二次迭代中,我们使用更新的总和和计数(sum,1)来调用它。闭包不应该一遍又一遍地使用参数(0,0)吗?
查看完整描述

2 回答

?
DIEA

TA贡献1820条经验 获得超2个赞

这是一种非常模糊的使用方式。但是,它确实有效。reduce


立即调用 ,返回 ,然后由 每个元素使用,从累加器开始,并在每次迭代中返回一个新的平均值,即使实际上只使用了最后一个值。它的工作原理是更新每次迭代的闭包中的 和 变量。function (sum, count)(0,0)function (avg, person)reduce0sumcount


计算平均值的一种更具可读性的方法是:reduce


const result = arr.reduce(function (acc, person) {

  if (person.name === "John") {

    return {

        sum: acc.sum + parseFloat(person.score),

        count: acc.count + 1

    }

  }

  return acc

}, { sum: 0, count: 0 })

console.log(result.sum / result.count)

但是,由于关键是计算一个人的平均分数,因此一种更具可读性且更短的方法是:


const johnsScores = arr.filter(person => person.name === 'John')

const total = johnsScores.reduce((acc, person) => acc + parseFloat(person.score), 0)

console.log(total / johnsScores.length)


查看完整回答
反对 回复 2022-08-18
?
慕慕森

TA贡献1856条经验 获得超17个赞

确定约翰的平均分数似乎有点复杂。它使用闭包来能够有条件地递增 的值。我试图使用运行值的日志来解释它。count


无论如何,平均确定可以大大简化(请参阅代码片段的第二部分)


const arr = [

  { name: "John", score: "8.8" },

  { name: "John", score: "8.6" },

  { name: "John", score: "9.0" },

  { name: "John", score: "8.3" },

  { name: "Tom", score: "7.9" } ];


// the outer function delivers the inner function

// the outer function uses 0, 0 as input initially

// The outer function does nothing with those values

// and it returns not a value, but the inner function.

// The inner function is run every iteration of reduce

// and in there the initial closed over values are 

// manipulated. That inner function returns the actual

// accumulator value (a running average)

const avgScoreDemo = arr.reduce(function(sum, count) {

  let outerValues = `outer sum: ${sum}, outer count: ${count}`;

  return function(avg, person) {

    console.log(outerValues +

      ` avg: ${avg}, inner sum ${sum}, inner count: ${count}`);

    if (person.name === "John") {

      sum += +person.score;

      return sum / ++count;

    }

    return avg;

  };

}(0, 0), 0);


// This can be simplified to

const avgScore = arr.reduce((sum, person) =>

    sum + (person.name === "John" ? +person.score : 0), 0) /

  arr.filter(v => v.name === "John").length;

console.log(avgScore);


// or using filter/index value

const avgScore2 = arr

  .filter( v => v.name === "John" )

  .reduce( (acc, person, i) =>

    ({ ...acc, sum: acc.sum + +person.score, 

        average: (acc.sum + +person.score) / ++i }), 

    { average: 0, sum: 0 } ).average;

console.log(avgScore2);

.as-console-wrapper {

  top: 0;

  max-height: 100% !important;

}


查看完整回答
反对 回复 2022-08-18
  • 2 回答
  • 0 关注
  • 116 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信