猿问

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

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)吗?


叮当猫咪
浏览 117回答 2
2回答

DIEA

这是一种非常模糊的使用方式。但是,它确实有效。reduce立即调用 ,返回 ,然后由 每个元素使用,从累加器开始,并在每次迭代中返回一个新的平均值,即使实际上只使用了最后一个值。它的工作原理是更新每次迭代的闭包中的 和 变量。function (sum, count)(0,0)function (avg, person)reduce0sumcount计算平均值的一种更具可读性的方法是:reduceconst 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)

慕慕森

确定约翰的平均分数似乎有点复杂。它使用闭包来能够有条件地递增 的值。我试图使用运行值的日志来解释它。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 toconst 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 valueconst 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;}
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答