以下是个人在工作中收藏总结的一些关于javascript数组方法reduce的相关代码片段,后续遇到其他使用这个函数的场景,将会陆续添加,这里作为备忘。

javascript数组那么多方法,为什么我要单挑reduce方法,一个原因是我对这个方法掌握不够,不能够用到随心所欲。另一个方面,我也感觉到了这个方法的庞大魅力,在许多的场景中发挥着神奇的作用。

理解reduce函数

reduce() 方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。

arr.reduce([callback, initialValue])

看如下例子:

let arr = [1, 2, 3, 4, 5];

// 10代表初始值,p代表每一次的累加值,在第一次为10

// 如果不存在初始值,那么p第一次值为1

// 此时累加的结果为15

let sum = arr.reduce((p, c) => p + c, 10); // 25

// 转成es5的写法即为:

var sum = arr.reduce(function(p, c) {

console.log(p);

return p + c;

}, 10);

片段一:字母游戏

const anagrams = str => {

if (str.length <= 2) {

return str.length === 2 ? [str, str[1] + str[0]] : str;

}

return str.split("").reduce((acc, letter, i) => {

return acc.concat(anagrams(str.slice(0, i) + str.slice(i + 1)).map(val => letter + val));

}, []);

}

anagrams("abc"); // 结果会是什么呢?

reduce负责筛选出每一次执行的首字母,递归负责对剩下字母的排列组合。

片段二:累加器

const sum = arr => arr.reduce((acc, val) => acc + val, 0);

sum([1, 2, 3]);

片段三:计数器

const countOccurrences = (arr, value) => arr.reduce((a, v) => v === value ? a + 1 : a + 0, 0);

countOccurrences([1, 2, 3, 2, 2, 5, 1], 1);

循环数组,每遇到一个值与给定值相等,即加1,同时将加上之后的结果作为下次的初始值。

片段四:函数柯里化

函数柯里化的目的就是为了储存数据,然后在最后一步执行。

const curry = (fn, arity = fn.length, ...args) =>

arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args);

curry(Math.pow)(2)(10);

curry(Math.min, 3)(10)(50)(2);

通过判断函数的参数取得当前函数的length(当然也可以自己指定),如果所传的参数比当前参数少,则继续递归下面,同时储存上一次传递的参数。

片段五:数组扁平化

const deepFlatten = arr =>

arr.reduce((a, v) => a.concat(Array.isArray(v) ? deepFlatten(v) : v), []);

deepFlatten([1, [2, [3, 4, [5, 6]]]]);

片段六:生成菲波列契数组

const fibonacci = n => Array(n).fill(0).reduce((acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i), []);

fibonacci(5);

片段七:管道加工器

const pipe = (...funcs) => arg => funcs.reduce((acc, func) => func(acc), arg);

pipe(btoa, x => x.toUpperCase())("Test");

通过对传递的参数进行函数加工,之后将加工之后的数据作为下一个函数的参数,这样层层传递下去。

片段八:中间件

const dispatch = action => {

console.log('action', action);

return action;

}

const middleware1 = dispatch => {

return action => {

console.log("middleware1");

const result = dispatch(action);

console.log("after middleware1");

return result;

}

}

const middleware2 = dispatch => {

return action => {

console.log("middleware2");

const result = dispatch(action);

console.log("after middleware2");

return result;

}

}

const middleware3 = dispatch => {

return action => {

console.log("middleware3");

const result = dispatch(action);

console.log("after middleware3");

return result;

}

}

const compose = middlewares => middlewares.reduce((a, b) => args => a(b(args)))

const middlewares = [middleware1, middleware2, middleware3];

const afterDispatch = compose(middlewares)(dispatch);

const testAction = arg => {

return { type: "TEST_ACTION", params: arg };

};

afterDispatch(testAction("1111"));

redux中经典的compose函数中运用了这种方式,通过对中间件的重重层叠,在真正发起action的时候触发函数执行。

片段九:redux-actions对state的加工片段

// redux-actions/src/handleAction.js

const handleAction = (type, reducer, defaultState) => {

const types = type.toString();

const [nextReducer, throwReducer] = [reducer, reducer];

return (state = defaultState, action) => {

const { type: actionType } = action;

if (!actionType || types.indexOf(actionType.toString()) === -1) {

return state;

}

return (action.error === true ? throwReducer : nextReducer)(state, action);

}

}

// reduce-reducers/src/index.js

const reduceReducer = (...reducers) => {

return (previous, current) => {

reducers.reduce((p, r) => r(p, current), previous);

}

}

// redux-actions/src/handleActions.js

const handleActions = (handlers, defaultState, { namespace } = {}) => {

// reducers的扁平化

const flattenedReducerMap = flattenReducerMap(handles, namespace);

// 每一种ACTION下对应的reducer处理方式

const reducers = Reflect.ownkeys(flattenedReducerMap).map(type => handleAction(

type,

flattenedReducerMap[type],

defaultState

));

// 状态的加工器,用于对reducer的执行

const reducer = reduceReducers(...reducers);

// reducer触发

return (state = defaultState, action) => reducer(state, action);

}

片段十:数据加工器

const reducers = {

totalInEuros: (state, item) => {

return state.euros += item.price * 0.897424392;

},

totalInYen: (state, item) => {

return state.yens += item.price * 113.852;

}

};

const manageReducers = reducers => {

return (state, item) => {

return Object.keys(reducers).reduce((nextState, key) => {

reducers[key](state, item);

return state;

}, {})

}

}

const bigTotalPriceReducer = manageReducers(reducers);

const initialState = { euros: 0, yens: 0 };

const items = [{ price: 10 }, { price: 120 }, { price: 1000 }];

const totals = items.reduce(bigTotalPriceReducer, initialState);

片段十一:对象空值判断

let school = {

name: 'Hope middle school',

created: '2001',

classes: [

{

name: '三年二班',

teachers: [

{ name: '张二蛋', age: 26, sex: '男', actor: '班主任' },

{ name: '王小妞', age: 23, sex: '女', actor: '英语老师' }

]

},

{

name: '明星班',

teachers: [

{ name: '欧阳娜娜', age: 29, sex: '女', actor: '班主任' },

{ name: '李易峰', age: 28, sex: '男', actor: '体育老师' },

{ name: '杨幂', age: 111, sex: '女', actor: '艺术老师' }

]

}

]

};

// 常规做法

school.classes &&

school.classes[0] &&

school.classes[0].teachers &&

school.classes[0].teachers[0] &&

school.classes[0].teachers[0].name

// reduce方法

const get = (p, o) => p.reduce((xs, x) => (xs && xs[x] ? xs[x] : null), o);

get(['classes', 0, 'teachers', 0, 'name'], school); // 张二蛋

片段十二:分组

const groupBy = (arr, func) =>

arr.map(typeof func === 'function' ? func : val => val[func]).reduce((acc, val, i) => {

acc[val] = (acc[val] || []).concat(arr[i]);

return acc;

}, {});

groupBy([6.1, 4.2, 6.3], Math.floor);

groupBy(['one', 'two', 'three'], 'length');

首先通过map计算出所有的键值,然后再根据建值进行归类

片段十三:对象过滤

const pick = (obj, arr) =>

arr.reduce((acc, curr) => (curr in obj && (acc[curr] = obj[curr]), acc), {});

pick({ a: 1, b: '2', c: 3 }, ['a', 'c']);

根据给出的键值来遍历,比较对象中是否存在相同键值的的值,然后通过逗号表达式把赋值后的对象赋给下一个的初始值

片段十四:数组中删除指定位置的值

const remove = (arr, func) =>

Array.isArray(arr)

? arr.filter(func).reduce((acc, val) => {

arr.splice(arr.indexOf(val), 1);

return acc.concat(val);

}, []) : [];

const arr = [1, 2, 3, 4];

remove(arr, n => n % 2 == 0);

首先根据filter函数过滤出数组中符合条件的值,然后使用reduce在原数组中删除符合条件的值,可以得出最后arr的值变成了[1, 3]

片段十五:promise按照顺序执行

const runPromisesInSeries = ps => ps.reduce((p, next) => p.then(next), Promise.resolve());

const delay = d => new Promise(r => setTimeout(r, d));

const print = args => new Promise(r => r(args));

runPromisesInSeries([() => delay(1000), () => delay(2000), () => print('hello')]);

片段十六:排序

const orderBy = (arr, props, orders) =>

[...arr].sort((a, b) =>

props.reduce((acc, prop, i) => {

if (acc === 0) {

const [p1, p2] = orders && orders[i] === 'desc' ? [b[prop], a[prop]] : [a[prop], b[prop]];

acc = p1 > p2 ? 1 : p1 < p2 ? -1 : 0;

}

return acc;

}, 0)

);

const users = [{ name: 'fred', age: 48 }, { name: 'barney', age: 36 }, { name: 'fly', age: 26 }];

orderBy(users, ['name', 'age'], ['asc', 'desc']);

orderBy(users, ['name', 'age']);

片段十七:选择

const select = (from, selector) =>

selector.split('.').reduce((prev, cur) => prev && prev[cur], from);

const obj = { selector: { to: { val: 'val to select' } } };

select(obj, 'selector.to.val');

js reduce实现中间件_js数组高阶方法reduce经典用法代码分享相关推荐

  1. 数组中常用的高阶方法

    一.操作方法 1.concat 如果传递的参数是一个数组或者多个数组,那么会将多个数组的每一个项都添加到原来的数组后面,然后返回这个数组,原数组不变. 例如: 2.slice slice方法接受两个参 ...

  2. swift 数组高阶使用(一)

    2019独角兽企业重金招聘Python工程师标准>>> ###swift 数组高阶使用 在使用数组的时候,我们通常会通过下标的方式来获得数组中的元素,但是有时候我们会需求会非常变态, ...

  3. js模板引擎art template数组渲染的方法

    转载:js模板引擎art template数组渲染的方法 JavaScript 模板引擎作为数据与界面分离工作中最重要一环,越来越受开发者关注,模板引擎种类也是五花八门,我就说几个安全性高.错误处理调 ...

  4. 【大数据开发】scala——tuple、list(含高阶方法)、wordcount案例、set、并行处理数据和sorted、sortBy、sortWith的区别

    文章目录 一.元组 1.1元组的定义.遍历 1.2元组的拉链.解链 二.list 2.1空list.list初始化.list遍历3种方式 2.2list的追加.拼接操作 2.3list的基本操作 2. ...

  5. scala条件替换_scala - 有没有办法用scala中的高阶方法替换嵌套的For循环 - SO中文参考 - www.soinside.com...

    有没有办法用scala中的高阶方法替换嵌套的For循环 问题描述 投票:0回答:1 我有一个mutableList,并希望获取所有行的总和,并根据某些条件将其行替换为其他值.下面的代码对我来说工作正常 ...

  6. java使用微信表情代码_iOS高仿微信表情输入功能代码分享

    最近项目需求,要实现一个类似微信的的表情输入,于是把微信的表情扒拉出来,实现了一把.可以从这里下载源码.看起来表情输入没有多少东西,不外乎就是用NSTextAttachment来实现图文混排,结果在实 ...

  7. 使用函数处理数组 高阶函数 js

    函数式编程 和lisp这种纯粹的函数式编程不一样,js可以实现其为函数式编程 使用函数处理数组 计算一个数组的平均值 // 定义一个用于计算和的函数 var sum = function(x, y){ ...

  8. js中every用法_js数组中的方法 some, every, filter, find,map, reduce讲解及使用场景

    前言 之前对数组的循环来说,我拿到代码就使用forEach循环,主要原因是我对数组的其他方法不是很了解,以及觉得forEach已经可以做到想要的效果,没必要在去使用其他方法,这都是对使用场景不了解导致 ...

  9. c2064 项不会计算为接受0个参数的函数_【JS必知必会】高阶函数详解与实战

    本文涵盖 前言 高级函数概念 函数作为参数的高阶函数 map filter reduce sort详解与实战 函数作为返回值的高阶函数 isType函数与add求和函数 如何自己创建高阶函数 前言 一 ...

最新文章

  1. 使用ildasm和ilasm修改dll
  2. python 使用 requests 做 http 请求
  3. centos纯命令行配置java环境
  4. 如何对mysql做物理备份_如何创建物理MySQL备份
  5. 助力句子变换:35W抽象、43W同义、13W简称三大知识库对外开源
  6. CAsyncSocket使用总结
  7. oracle 安装raid卡驱动,centos安装raid卡驱动总结
  8. 广州科二化龙考场_广州考驾照[科目二]化龙考场.考试详解
  9. cocos2d-x中setcolor中的rgb颜色值设置
  10. 移动apn接入点哪个快_提升移动联通电信网速
  11. ddl是什么意思网络语_跟随你大学的流行词语 DDL 你竟还不知道?
  12. 产品经理不再纸上谈兵——关于用户默认头像的思考
  13. Failed to open /var/lib/samba/private/secrets.tdb
  14. 搞死SAP系统系列 让PO系统宕机
  15. 化工专业和计算机专业哪个好就业前景,2019化学工程与工艺专业就业前景和就业方向分析...
  16. Java 绘制带圆角头像的二维码
  17. WorldModel世界模型代码训练实录
  18. softer soft parse
  19. listen的第二个参数详解
  20. python爬虫实战练习 --- 喜马拉雅免费音频 下载到本地

热门文章

  1. RFID图书管理系统程序源代码(转)
  2. Leetcode No.146 ****
  3. 内存容量出现异常的解决办法
  4. C语言宏定义##连接符和#符的使用及其它宏定义注意事项
  5. BookSmart Self Publishing
  6. 免安装Mysql在Mac中的神坑之Access denied for user 'root'@'localhost' (using password: YES)
  7. http --- cookie与会话跟踪
  8. 亚马逊Rekognition发布针对人脸检测、分析和识别功能的多项更新
  9. SystemCenter2012SP1实践(19)集成WSUS更新服务器2012
  10. python 操作RabbitMQ