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

以下是个人在工作中收藏总结的一些关于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');

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/260006.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

struts2的s:iterator 标签 详解

struts2的s&#xff1a;iterator 可以遍历 数据栈里面的任何数组&#xff0c;集合等等 以下几个简单的demo&#xff1a;s:iterator 标签有3个属性&#xff1a; value&#xff1a;被迭代的集合 id &#xff1a;指定集合里面的元素的id status 迭代元素的索引1:jsp…

Protocol Buffers的应用

1. Protocol Buffers的介绍 Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then …

编程提高:一天一道编程题

1.文本操作 逆转字符串——输入一个字符串&#xff0c;将其逆转并输出。 拉丁猪文字游戏——这是一个英语语言游戏。基本规则是将一个英语单词的第一个辅音音素的字母移动到词尾并且加上后缀-ay&#xff08;譬如“banana”会变成“anana-bay”&#xff09;。可以在维基百科上了…

android自验签名证书,没有以前的互联网连接,无法验证Android自签名证书

使用SSL基础架构&#xff1a;我们有一个有效的客户端/服务器设置,其中Android版本4.2和4.4的手机充当客户端,必须通过其自签名SSL证书验证服务器.问题&#xff1a;只要设备在尝试连接之前至少有一次互联网访问权限,服务器证书验证就会起作用.但是,如果执行恢复出厂设置且设备直…

asp.net缓存(二)

ASP.NET页面局部缓存 有时缓存整个页面是不现实的&#xff0c;因为页的某些部分可能在每次请求时都需要变化。在这些情况下&#xff0c;只能缓存页的一部分。顾名思义&#xff0c;页面部分缓存是将页面部分内容保存在内存中以便响应用户请求&#xff0c;而页面其他部分内容则为…

学习C# - Hello,World!

第一天学C#,开始学着写一些学习笔记&#xff0c;看了一下传智播客的视频&#xff0c;按照传智播客的教学顺序&#xff0c;开始学习。 class Program{static void Main(string[] args){Console.WriteLine("Hello World!");//自动添加回车换行Console.Write("Hell…

android获取button宽度,android – 如何获得Button的高度和宽度

我创建了一系列按钮.现在我想找到按钮的高度和宽度,为此我使用了getWidth()和getHeight().但问题是它总是返回0.为什么会发生这种情况&#xff1f;我发送了我的代码,请检查是否有任何问题.int x,y;LinearLayout layoutVertical (LinearLayout) findViewById(R.id.liVLayout);L…

java执行sql列名无效_嵌套异常是java.sql.SQLException:无效的列名ORACLE

我尝试在Java中使用JdbcTemplate执行以下oracle查询&#xff1a;select RESOURCE_IDfrom REPRO_PRINTING_JOBwhere (USER_ID? and PRINTING_CENTER_ID?)group by RESOURCE_IDunion allselect RESOURCE_IDfrom REPRO_PRINTING_JOB_OLDwhere (USER_ID? and PRINTING_CENTER_ID…

(七)Maven使用的最佳实践

这里说一下在使用Maven过程中不是必须的&#xff0c;但十分有用的几个实践&#xff0c;关键时刻或许能解决您的问题。 1.设置MAVEN_OPTS环境变量 通常需要设置MAVEN_OPTS的值为-Xms128m -Xmx512m&#xff0c;因为Java默认的最大可用内存往往不能够满足Maven运行的需要&#xff…

android beam传输速率,无线网络的速率为何不能达到最大值

1、无线速率可以达到最大值&#xff0c;只是发送速率和传输流量是两个概念&#xff0c;通俗点讲&#xff0c;无线的发送速率是把信号以指定速率发出去(信号好的时候以高速率发&#xff0c;信号差的时候以低速率发)。传输流量是指单位时间内传输的数据量&#xff0c;大部分用户关…

【SMTP 补录 Apache服务】

【补录&#xff0c;续】1.【配置空壳邮件接受】【mta】【前置&#xff1a;在/etc/named.rfc1912.zones 添加一个可以接受邮件的域hxl.org&#xff08;与你数据库中写的向对应&#xff09;,这个域的所在ip就是你机子的&#xff0c;因为要从你的机子转发】 【配置该机的vim/etc/…

image打开rgb16 qt_QT中显示图像数据

一般图像数据都是以RGBRGBRGB……字节流的方式(解码完成后的原始图像流)&#xff0c;我说成字节流&#xff0c;那就表明R&#xff0c;G&#xff0c;B的值各占一个字节&#xff0c;在编程时表示的就是unsigned char * data。我们先来看一下QT中的QImage对象。在加载data数据前&a…

开启chrome默认支持ipv6

在快捷方式后面的属性后面输入 --enable-ipv6 以下为转载&#xff1a; [转载]chrome开启或关闭IPV6方法 (2012-05-27 17:54:06) 转载▼ 标签&#xff1a; 转载 分类&#xff1a; 技术 原文地址&#xff1a;chrome开启或关闭IPV6方法作者&#xff1a;余鲲涛 chrome和firefox都是…

Nginx安装部署

转&#xff1a;http://www.cnblogs.com/zhuhongbao/archive/2013/06/04/3118061.html Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器&#xff0c;也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开…

android ble 连续读写,Android BLE实现对蓝牙的读写

【实例简介】通过修改官方的demo实现对蓝牙的读写操作&#xff0c;详细http://blog.csdn.net/chenfengdejuanlian/article/details/45787123【实例截图】【核心代码】BluetoothLe_demo0└── BluetoothLe_demo0├── AndroidManifest.xml├── bin│ ├── AndroidManife…

一分钟经理人

原创2016-12-0858沈剑 零、缘起近期公司再做管理者培训&#xff0c;偶老大推荐了一本薄薄的《一分钟经理人》&#xff0c;斯宾塞.约翰逊&#xff0c;花了1小时读完有感&#xff0c;沉淀一篇阅读笔记&#xff0c;故有此文。一、前言常见经理人有两类&#xff1a;&#xff08;1&a…

python写机器人程序_用Python写的一个多线程机器人聊天程序

本人是从事php开发的, 近来想通过php实现即时通讯(兼容windows)。后来发现实现起来特别麻烦&#xff0c; 就想到python。听说这家伙在什么地方都能发挥作用。所以想用python来做通讯模块。。。所以主要学习pythonn的多线程和tcp连接。但是没有用过python&#xff0c; 所有在学习…

[转] 前端中的MVC

MVC是一种设计模式&#xff0c;它将应用划分为3个部分&#xff1a;数据&#xff08;模型&#xff09;、展现层&#xff08;视图&#xff09;和用户交互&#xff08;控制器&#xff09;。其中&#xff1a; M - MODEL&#xff08;模型&#xff09; V - VIEW&#xff08;视图&…

ipoo3可以用鸿蒙,iqooneo3支持无线充电吗_iqooneo3可以无线充电吗

iqoo neo3在不高的价格上还保证了自己的品质&#xff0c;有很高的性能&#xff0c;很不错的屏幕。那么这款手机可以支持无线充电吗&#xff1f;小编为大家介绍关于iqoo neo3的充电方面。1.iqoo neo3可以支持无线充电吗iQOO Neo3 配备了 44W 超级闪充&#xff0c;属于小刀&#…

红帽Linux故障定位技术详解与实例(1)

红帽Linux故障定位技术详解与实例(1) 2011-09-28 14:26 圈儿 BEAREYES.COM 我要评论(0) 字号&#xff1a;T | T在线故障定位就是在故障发生时, 故障所处的操作系统环境仍然可以访问&#xff0c;故障处理人员可通过console, ssh等方式登录到操作系统上&#xff0c;在shell上执行…