JavaScript的reduce方法在对象上无法使用

3

我正在尝试理解reduce的工作原理。

var expense = [
    {
        item: "Bed",
        cost: 1499,
        date: "02-23-2018"
    },
    {
        item: "Phone",
        cost: 2499,
        date: "02-23-2018"
    },
    {
        item: "Book",
        cost: 400,
        date: "02-23-2018"
    },
    {
        item: "Mattress",
        cost: 700,
        date: "02-23-2018"
    },
    {
        item: "Food",
        cost: 300,
        date: "02-23-2018"
    }
];

var totalExpense = expense.reduce(function (a, b) {
    console.log(a.cost, b.cost);
    return a.cost + b.cost;
});

console.log(totalExpense);

这将使得totalExpense的值为NaN

输出结果:

1499 2499
undefined 400
undefined 700
undefined 300
NaN

当我使用一个简单的支出数组进行相同的操作时,它能够正常工作。
7个回答

20

传递给 reduce 回调函数的第一个参数是先前的值 (a) - 或者是您传递给 reduce 的第二个参数 (初始值)

[].reduce(function(a, b) { ... }, 0);
          ^ callback              ^ initial value
a将保存每次迭代的结果,因此要获取所有成本的总和,只需添加b.cost即可。

var expense = [{
    item: 'Bed',
    cost: 1499,
    date: '02-23-2018'
  },
  {
    item: 'Phone',
    cost: 2499,
    date: '02-23-2018'
  },
  {
    item: 'Book',
    cost: 400,
    date: '02-23-2018'
  },
  {
    item: 'Mattress',
    cost: 700,
    date: '02-23-2018'
  },
  {
    item: 'Food',
    cost: 300,
    date: '02-23-2018'
  }
];
var totalExpense = expense.reduce(function(a, b) {
  return a + b.cost;
}, 0);

console.log(totalExpense);

使用ES6语法,您可以将其变为一行代码。

var totalExpense = expense.reduce((a, {cost}) => a + cost, 0);

1
你需要提供一个初始值,该值具有一个名为cost的字段,以便在累加器中引用它。并且你需要返回该对象:
expense.reduce(function(acc, curr){
    console.log(acc.cost, curr.cost);
    acc.cost += curr.cost;
    return acc;
    }, { cost: 0 });

请注意,变量名比 a b 更有意义。这将使您的代码更易于理解。 Array.prototype.reduce 回调应具有累加器和当前值。 将它们命名为此以帮助自己。 初始值提供了一个带有 cost 字段的对象,您可以在其中写下累积值。
请注意,如果您想要,您也可以在此处仅使用普通变量。 如果实际上不需要对象:
var total = expense.reduce(function(acc, curr){
    acc += curr.cost;
    return acc;
    }, 0);
 console.log(total);
 >> 5398

0
你需要 return 下一个 a 应该是什么。 a.cost + b.cost 是一个数字。它没有一个 cost 属性,所以在第一次迭代后 a.cost 将会是 undefined
只需提供一个起始值 0。同时考虑给你的参数更合适的名称。
var totalExpense = expense.reduce(function(sum, item){
  return sum + item.cost;
}, 0);

0

你需要一个初始值。reduce函数将累积的值作为第一个参数,集合的下一个元素作为第二个参数。

var totalExpense = expense.reduce(function(accumulator, current) {
console.log({ accumulator: accumulator, currentCost: current.cost });
return accumulator + current.cost;
}, 0);

console.log({ totalExpense: totalExpense });

0
//通过reduce方法计算总成本 let totalExpense = expense.reduce((tem,val) => tem+=val.cost,0) console.log(totalExpense)

-1
expense.reduce((sum, cur) => ({ cost: sum.cost + cur.cost })).cost;

更新 正如@Viktor所指出的,我之前没有考虑到特殊情况。

function getTotelExpense(expense) {
    if (expense.length > 0 && expense[0].hasOwnProperty("cost"))
        return expense.reduce((sum, cur) => ({ cost: sum.cost + cur.cost })).cost;
    else return 0;
}

你可以在TypeError: Reduce of empty array with no initial value | MDN中了解更多。


这个 reduce 函数对于空列表会返回 undefined。 如果使用 undefined.cost 会导致崩溃。实际上我错了,运行代码时会立即出现 TypeError: Reduce of empty array with no initial value - Viktor
@Viktor 谢谢。我没有考虑到空的情况。 - Jun Yu

-2

这里有另一种使用通用函数foldMap的方法 - 如果您想了解更多关于这个美妙函数的指导,我建议观看这个视频

const totalExpense =
  expense.foldMap (item => item.cost, 0)

console.log (totalExpense)
// 5398

为此,您需要定义Array.prototype.foldMapNumber.prototype.concat - 但是实现和定义它们的位置由您决定。

Array.prototype.foldMap = function (f, acc)
{
  return this.reduce ((acc, x, i) =>
    acc.concat (f (x, i, this)), acc)
}

Number.prototype.concat = function (m)
{
  return this + m
}

这里是一个可运行的代码粘贴

Array.prototype.foldMap = function (f, acc)
{
  return this.reduce ((acc, x, i) =>
    acc.concat (f (x, i, this)), acc)
}

Number.prototype.concat = function (m)
{
  return this + m
}

const expense =
  [ { item: 'Bed'
    , cost: 1499
    , date: '02-23-2018'
    }
  , { item: 'Phone'
    , cost: 2499
    , date: '02-23-2018'
    }
  , { item: 'Book'
    , cost: 400
    , date: '02-23-2018'
    }
  , { item: 'Mattress'
    , cost: 700
    , date: '02-23-2018'
    }
  , { item: 'Food'
    , cost: 300
    , date: '02-23-2018'
    }
  ]
  
const totalExpense =
  expense.foldMap (item => item.cost, 0)

console.log(totalExpense)
// 5398


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接