深入浅出之Reduce(简易版redux)

77 阅读2分钟

Reduce原理

reduce() 实例方法按Array顺序对数组的每个元素执行用户提供的“reducer”回调函数,并传入前一个元素计算的返回值。对数组的所有元素运行 Reducer 的最终结果是一个值。

第一次运行回调时,没有“上一次计算的返回值”。如果提供了,可以使用初始值代替它。否则,索引 0 处的数组元素将用作初始值,迭代从下一个元素开始(索引 1 而不是索引 0)。

我们利用以上特性,进行一些操作

常见应用场景

数组求和

// 关于reduce
console.log("--------------------------数组求和--------------------------------");
const numbers: number[] = [1, 2, 5, 6, 10];
const sum: number = numbers.reduce((acc, curr) => {
    console.log(acc, curr);
    return acc + curr;
}, 0);
console.log("结果是", sum);

image.png

扁平化数组

console.log("--------------------------扁平化数组--------------------------------");
const nestedArray: number[][] = [[1, 2], [3, 4], [5, 6]];
const flattenedArray: number[] = nestedArray.reduce((acc, curr) => {
    console.log(acc, curr);
    return acc.concat(curr);
}, []);
console.log("结果是", flattenedArray);

image.png

对象分组

console.log("--------------------------对象分组--------------------------------");
interface Person {
    name: string;
    age: number;
}
const people: Person[] = [
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 25 },
    { name: 'Dave', age: 30 }
];
const groupedByAge: { [key: number]: Person[] } = people.reduce((acc, curr) => {
    if (!acc[curr.age]) {
        acc[curr.age] = [];
    }
    acc[curr.age].push(curr);
    console.log(acc, curr);
    return acc;
}, {});
console.log("结果是:", groupedByAge);

image.png

统计次数

console.log("--------------------------统计次数--------------------------------");
const fruits: string[] = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
const fruitCounts: { [key: string]: number } = fruits.reduce((acc, curr) => {
  acc[curr] = (acc[curr] || 0) + 1;
  console.log(acc, curr);
  return acc;
}, {});
console.log("结果是", fruitCounts);

image.png

组合函数

console.log("--------------------------组合函数--------------------------------");
const add5 = (x: number): number => x + 5;
const multiply3 = (x: number): number => x * 3;
const subtract2 = (x: number): number => x - 2;
const composedFunctions: ((x: number) => number)[] = [add5, multiply3, subtract2];
const result: number = composedFunctions.reduce((acc, curr) => {
    console.log(acc, curr);
    return curr(acc);
}, 10);
console.log("结果是", result);

image.png

数组去重

console.log("--------------------------数组去重--------------------------------");
const numbers_2: number[] = [1, 2, 3, 2, 4, 3, 5, 1, 6];
const uniqueNumbers: number[] = numbers_2.reduce((acc: number[], curr) => {
  if (!acc.includes(curr)) {
    acc.push(curr);
  }
  console.log(acc, curr);
  return acc;
}, []);
console.log("结果是", uniqueNumbers);

image.png

求平均值

console.log("--------------------------求平均值--------------------------------");
const grades: number[] = [85, 90, 92, 88, 95];
const average: number = grades.reduce((acc, curr, index, array) => {
  acc += curr;
  if (index === array.length - 1) {
    return acc / array.length;
  }
  console.log(acc, curr);
  return acc;
}, 0);
console.log("结果是", average);

image.png

实现简单的类似Redux的状态管理

interface State {
    count: number;
    todos: string[];
}

interface Action {
    type: string;
    payload?: any;
}

const initialState: State = {
    count: 0,
    todos: [],
};

const actions: Action[] = [
    { type: 'INCREMENT_COUNT' },
    { type: 'ADD_TODO', payload: 'Learn Array.reduce()' },
    { type: 'INCREMENT_COUNT' },
    { type: 'ADD_TODO', payload: 'Master TypeScript' },
];

const reducer = (state: State, action: Action): State => {
    switch (action.type) {
        case 'INCREMENT_COUNT':
            return { ...state, count: state.count + 1 };
        case 'ADD_TODO':
            return { ...state, todos: [...state.todos, action.payload] };
        default:
            return state;
    }
};

const finalState: State = actions.reduce(reducer, initialState);
console.log(finalState);

image.png

不做多的赘述,上述的例子都是比较清楚的,后续会有详细的解析Redux的文章,正在完善~

参考文章

Array.prototype.reduce()

# 数组的reduce方法是最棒的,你不知道的reduce的高级用法