在使用reduce时突然发现reduce似乎可以遍历对象嵌套结构
function getObjectPropertyValue(obj, propertyPath) {
return propertyPath.split('.').reduce((result, key) => result[key], obj);
}
const person = {
name: 'John',
address: {
city: 'New York',
street: '123 ABC Street'
}
};
const name = getObjectPropertyValue(person, 'name');
console.log(name); // John
const city = getObjectPropertyValue(person, 'address.city');
console.log(city); // New York
const street = getObjectPropertyValue(person, 'address.street');
console.log(street); // 123 ABC Street
查询文档:Array methods
When we need to iterate over an array – we can use forEach
, for
or for..of
.
When we need to iterate and return the data for each element – we can use map
.
The methods arr.reduce and arr.reduceRight also belong to that breed, but are a little bit more intricate. They are used to calculate a single value based on the array.
The syntax is:
let value = arr.reduce(function(accumulator, item, index, array) {
// ...
}, [initial]);
The function is applied to all array elements one after another and “carries on” its result to the next call.
Arguments:
accumulator
– is the result of the previous function call, equals initial
the first time (if initial
is provided).item
– is the current array item.index
– is its position.array
– is the array.As function is applied, the result of the previous function call is passed to the next one as the first argument.
So, the first argument is essentially the accumulator that stores the combined result of all previous executions. And at the end it becomes the result of reduce
.
Sounds complicated?
The easiest way to grasp that is by example.
Here we get a sum of an array in one line:
let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((sum, current) => sum + current, 0);
alert(result); // 15
The function passed to reduce
uses only 2 arguments, that’s typically enough.
Let’s see the details of what’s going on.
sum
is the initial
value (the last argument of reduce
), equals 0
, and current
is the first array element, equals 1
. So the function result is 1
.sum = 1
, we add the second array element (2
) to it and return.sum = 3
and we add one more element to it, and so on…The calculation flow:
Or in the form of a table, where each row represents a function call on the next array element:
sum |
current |
result | |
---|---|---|---|
the first call | 0 |
1 |
1 |
the second call | 1 |
2 |
3 |
the third call | 3 |
3 |
6 |
the fourth call | 6 |
4 |
10 |
the fifth call | 10 |
5 |
15 |
Here we can clearly see how the result of the previous call becomes the first argument of the next one.
We also can omit the initial value:
let arr = [1, 2, 3, 4, 5];
// removed initial value from reduce (no 0)
let result = arr.reduce((sum, current) => sum + current);
alert( result ); // 15
The result is the same. That’s because if there’s no initial, then reduce
takes the first element of the array as the initial value and starts the iteration from the 2nd element.
The calculation table is the same as above, minus the first row.
But such use requires an extreme care. If the array is empty, then reduce
call without initial value gives an error.
Here’s an example:
let arr = [];
// Error: Reduce of empty array with no initial value
// if the initial value existed, reduce would return it for the empty arr.
arr.reduce((sum, current) => sum + current);
So it’s advised to always specify the initial value.
The method arr.reduceRight does the same, but goes from right to left.
可以看出官方推荐的用法是使用这个累加器可以方便的计算一个数组元素的和,通过 return 可以把每次迭代的值返回给total作为下一次的初始值,如果我们 return 一个对象的话,不就可以依次读取多层嵌套的对象的属性了吗?
我们将子级结构作为上一次的值返回,从而实现遍历多层嵌套结构。在reduce函数的回调函数中,根据需要选择将子级结构与累积值(上一次的值)进行合并或者进行其他操作,并将结果作为下一次迭代的累积值返回。
另外reduce还可以实现数据转换与映射,使用 reduce
函数将一个数据集转换为另一种格式的数据集:
const people = [
{ name: 'John', age: 25 },
{ name: 'Jane', age: 30 },
{ name: 'Mike', age: 35 }
];
const nameAgeMap = people.reduce((acc, curr) => {
acc[curr.name] = curr.age;
return acc;
}, {});
console.log(nameAgeMap); // { John: 25, Jane: 30, Mike: 35 }