Yang's Blog

JavaScript中reduce方法

reduce() 方法是 ECMAScript5 规范中出现的数组方法。在平时的工作中,相信大家使用的场景并不多,一般而言,可以通过 reduce 方法实现的逻辑都可以通过 forEach 方法来变相的实现,虽然不清楚浏览器的js引擎是如何在C++层面实现这两个方法,但是可以肯定的是 reduce 方法肯定也存在数组的遍历,在具体实现细节上是否针对数组项的操作和存储做了什么优化,则不得而知。

reduce() 在数组中的应用:

reduce() 方法有两个参数,第一个参数是一个 callback,用于针对数组项的操作;第二个参数则是传入的初始值,这个初始值用于单个数组项的操作。需要注意的是,reduce 方法返回值并不是数组,而是形如初始值的经过叠加处理后的操作。

reduce() 方法最常见的场景就是叠加。

1
2
3
4
5
6
7
8
9
var items = [10, 100, 1000];
var reducer = function add(sumSoFar, item) {
return sumSoFar + item;
};
var total = items.reduce(reducer, 0);
console.log(total); // 1110

可以看出,reduce()函数根据初始值0,不断的进行叠加,完成最简单的总和的实现。

前文中也提到,reduce() 函数的返回结果类型和传入的初始值相同,上个实例中初始值为 number 类型,同理,初始值也可为 object 类型。

1
2
3
4
5
6
7
8
9
10
var items = [10, 100, 1000];
var reducer = function add(sumSoFar, item) {
sumSoFar.sum = sumSoFar.sum + item;
return sumSoFar;
};
var total = items.reduce(reducer, {sum: 0});
console.log(total); // {sum:1110}

多重叠加:

使用 reduce() 方法可以完成多维度的数据叠加。如上例中的初始值 {sum: 0} ,这仅仅是一个维度的操作,如果涉及到了多个属性的叠加,如 {sum: 0,totalInEuros: 0,totalInYen: 0} ,则需要相应的逻辑进行处理。

在下面的方法中,采用分而治之的方法,即将 reduce() 函数第一个参数 callback 封装为一个数组,由数组中的每一个函数单独进行叠加并完成 reduce 操作。所有的一切通过一个 manager 函数来管理流程和传递初始参数。

1
2
3
4
5
6
7
8
9
10
11
var manageReducers = function(reducers) {
return function(state, item) {
return Object.keys(reducers).reduce(
function(nextState, key) {
reducers[key](state, item);
return state;
},
{}
);
}
};

上面就是 manager 函数的实现,它需要 reducers 对象作为参数,并返回一个 callback 类型的函数,作为 reduce 的第一个参数。在该函数内部,则执行多维的叠加工作(Object.keys())。

通过这种分治的思想,可以完成目标对象多个属性的同时叠加,完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var reducers = {
totalInEuros : function(state, item) {
return state.euros += item.price * 1;
},
totalInYen : function(state, item) {
return state.yens += item.price * 2;
}
};
var manageReducers = function(reducers) {
return function(state, item) {
return Object.keys(reducers).reduce(
function(nextState, key) {
reducers[key](state, item);
return state;
},
{}
);
}
};
var bigTotalPriceReducer = manageReducers(reducers);
var initialState = {euros:0, yens: 0};
var items = [{price: 10}, {price: 100}, {price: 1000}];
var totals = items.reduce(bigTotalPriceReducer, initialState);
console.log(totals); // {euros:1110, yens:2220}

当然,如果你更喜欢函数式编程的话

如果 HaskellIPA 那么 JavaScript 就是 O'Douls。就是说,与 Haskell 不同,JavaScript 不是函数式编程语言,不过它仍然有一点函数式的意味。函数式语言更整洁也更容易测试,所以你最好能喜欢上这种编程风格。

一般 JavaScript 写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const programmerOutput = [
{
name: 'Uncle Bobby',
linesOfCode: 500
}, {
name: 'Suzie Q',
linesOfCode: 1500
}, {
name: 'Jimmy Gosling',
linesOfCode: 150
}, {
name: 'Gracie Hopper',
linesOfCode: 1000
}
];
var totalOutput = 0;
for (var i = 0; i < programmerOutput.length; i++) {
totalOutput += programmerOutput[i].linesOfCode;
}
console.log(totalOutput); // 3150

而函数式编程的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const programmerOutput = [
{
name: 'Uncle Bobby',
linesOfCode: 500
}, {
name: 'Suzie Q',
linesOfCode: 1500
}, {
name: 'Jimmy Gosling',
linesOfCode: 150
}, {
name: 'Gracie Hopper',
linesOfCode: 1000
}
];
var totalOutput = programmerOutput
.map((programmer) => programmer.linesOfCode)
.reduce((acc, linesOfCode) => acc + linesOfCode, 0)
console.log(totalOutput); // 3150

是不是发现函数式编程更简单呢 ^__^ 希望可以爱上它 ♥

Enjoy it ? Donate me ! 欣赏此文?求鼓励,求支持!