js数组方法reduce经典用法代码分享


Posted in Javascript onJanuary 07, 2018

以下是个人在工作中收藏总结的一些关于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经典用法代码内容,感谢你对三水点靠木的支持。

Javascript 相关文章推荐
网页图片延时加载的js代码
Apr 22 Javascript
基于jquery的blockui插件显示弹出层
Apr 14 Javascript
node.js中的events.emitter.listeners方法使用说明
Dec 10 Javascript
JavaScript使用ActiveXObject访问Access和SQL Server数据库
Apr 02 Javascript
JQuery给网页更换皮肤的方法
May 30 Javascript
kindeditor编辑器点中图片滚动条往上顶的bug
Jul 05 Javascript
jquery简单实现网页层的展开与收缩效果
Aug 07 Javascript
jquery的幻灯片图片切换效果代码分享
Sep 07 Javascript
jQuery each函数源码分析
May 25 Javascript
JS排序之快速排序详解
Apr 08 Javascript
vue-router 权限控制的示例代码
Sep 21 Javascript
详解基于Vue的支持数据双向绑定的select组件
Sep 02 Javascript
javascript中的replace函数(带注释demo)
Jan 07 #Javascript
基于JavaScript实现简单的音频播放功能
Jan 07 #Javascript
js实现复制功能(多种方法集合)
Jan 06 #Javascript
tangram.js库实现js类的方式实例分析
Jan 06 #Javascript
JavaScript寄生组合式继承实例详解
Jan 06 #Javascript
基于jquery trigger函数无法触发a标签的两种解决方法
Jan 06 #jQuery
JS实现非首屏图片延迟加载的示例
Jan 06 #Javascript
You might like
PHP与MySQL开发中页面出现乱码的一种解决方法
2007/07/29 PHP
php &amp;&amp; 逻辑与运算符使用说明
2010/03/04 PHP
全面解析PHP操作Memcache基本函数
2016/07/14 PHP
通过PHP设置BugFree获取邮箱通知
2019/04/25 PHP
Jquery cookie操作代码
2010/03/14 Javascript
使用jquery中height()方法获取各种高度大全
2014/04/02 Javascript
兼容主流浏览器的jQuery+CSS 实现遮罩层的简单代码
2014/10/14 Javascript
《JavaScript DOM 编程艺术》读书笔记之JavaScript 语法
2015/01/09 Javascript
JavaScript中的对象与JSON
2015/07/03 Javascript
cocos2dx骨骼动画Armature源码剖析(三)
2015/09/08 Javascript
JavaScript基础知识及常用方法总结
2016/01/10 Javascript
微信小程序 slider 详解及实例代码
2017/01/10 Javascript
浅谈原生JS实现jQuery的animate()动画示例
2017/03/08 Javascript
AngularJS路由Ui-router模块用法示例
2017/05/29 Javascript
JS实现前端动态分页码代码实例
2020/06/02 Javascript
[51:26]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#3Secret VS OG第二局
2016/03/03 DOTA
[01:00:12]2018DOTA2亚洲邀请赛 4.7 淘汰赛 VP vs LGD 第一场
2018/04/09 DOTA
Python修改Excel数据的实例代码
2013/11/01 Python
wxPython窗口中文乱码解决方法
2014/10/11 Python
栈和队列数据结构的基本概念及其相关的Python实现
2015/08/24 Python
SVM基本概念及Python实现代码
2017/12/27 Python
Python+Turtle动态绘制一棵树实例分享
2018/01/16 Python
python实现守护进程、守护线程、守护非守护并行
2018/05/05 Python
Python列表解析操作实例总结
2020/02/26 Python
python定义类的简单用法
2020/07/24 Python
入党自我评价范文
2014/02/02 职场文书
派出所所长先进事迹
2014/05/19 职场文书
公务员四风问题对照检查材料整改措施
2014/09/26 职场文书
小学感恩节活动策划方案
2014/10/06 职场文书
通知的格式范文
2015/04/27 职场文书
党员志愿者服务倡议书
2015/04/29 职场文书
闪闪的红星观后感
2015/06/08 职场文书
校长新学期致辞
2015/07/30 职场文书
利用Sharding-Jdbc进行分库分表的操作代码
2022/01/22 Java/Android
Java中Quartz高可用定时任务快速入门
2022/04/03 Java/Android
Windows 64位 安装 mysql 8.0.28 图文教程
2022/04/19 MySQL