簡體   English   中英

累加器 function 內部 reduce 被 Javascript 中的 function 包裹,使用閉包

[英]Accumulator function inside reduce is wrapped by a function in Javascript using closure

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 中究竟是如何工作的。 我對帶有累加器和迭代元素的 function 被另一個 function 包裹這一事實感到驚訝。 Isn't reduce supposed to accept a function with the the accumulator and the iterated element, then how come the reduce function still works despite the fact that the accumulator function with the iterated element with avg is wrapped by another function?

另外,為什么我們用 (0,0) 的閉包來調用 function,但是在第二次迭代中,我們用更新的 sum 和 count (sum, 1) 調用它。 閉包不應該一遍又一遍地使用 arguments (0, 0) 嗎?

這是使用reduce的一種非常模糊的方式。 但它確實有效。

function (sum, count)立即使用(0,0)調用,返回function (avg, person) ,然后由reduce用於每個元素,從累加器0開始,並為每個元素返回一個新的平均值即使只實際使用了最后一個值,也會進行迭代。 它通過為每次迭代更新閉包內的sumcount變量來工作。

使用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)

確定約翰的平均分數似乎有點復雜。 它使用閉包能夠有條件地增加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; }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM