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 相关文章推荐
Firebug入门指南(Firefox浏览器)
Aug 21 Javascript
JS模板实现方法
Apr 03 Javascript
关于JS数组追加数组采用push.apply的问题
Jun 09 Javascript
js确认删除对话框适用于a标签及submit
Jul 10 Javascript
JavaScript中的类与实例实现方法
Jan 23 Javascript
两款JS脚本判断手机浏览器类型跳转WAP手机网站
Oct 16 Javascript
JavaScript 数组中最大最小值
Jun 05 Javascript
bootstrap laydate日期组件使用详解
Jan 04 Javascript
详解ES6中的Map与Set集合
Mar 22 Javascript
深入理解vue中的slot与slot-scope
Apr 22 Javascript
VuePress 中如何增加用户登录功能
Nov 29 Javascript
关于Vue中的options选项
Mar 22 Vue.js
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
可兼容php5与php7的cURL文件上传功能实例分析
2018/05/11 PHP
在Laravel中使用DataTables插件的方法
2018/05/29 PHP
点击下载链接 弹出页面实现代码
2009/10/01 Javascript
javascript工具库代码
2012/03/29 Javascript
javascript 3d 逐侦产品展示(核心精简)
2014/03/26 Javascript
浅谈javascript中自定义模版
2015/01/29 Javascript
实现音乐播放器的代码(html5+css3+jquery)
2015/08/04 Javascript
AngularJS中的表单简单入门
2016/07/28 Javascript
Bootstrap Table使用心得总结
2016/11/29 Javascript
深入探究node之Transform
2017/07/20 Javascript
微信小程序录音与播放录音功能
2017/12/25 Javascript
Vue.js轮播图走马灯代码实例(全)
2019/05/08 Javascript
微信小程序实现星级评价
2019/11/20 Javascript
Vue使用虚拟dom进行渲染view的方法
2019/12/26 Javascript
解决vue打包 npm run build-test突然不动了的问题
2020/11/13 Javascript
如何利用nodejs自动定时发送邮件提醒(超实用)
2020/12/01 NodeJs
[06:45]DOTA2-DPC中国联赛 正赛 Magma vs LBZS 选手采访
2021/03/11 DOTA
python人人网登录应用实例
2014/09/26 Python
python 生成器协程运算实例
2017/09/04 Python
python采集微信公众号文章
2018/12/20 Python
pycharm访问mysql数据库的方法步骤
2019/06/18 Python
简单了解django索引的相关知识
2019/07/17 Python
python gdal安装与简单使用
2019/08/01 Python
Python搭建代理IP池实现接口设置与整体调度
2019/10/27 Python
解决redis与Python交互取出来的是bytes类型的问题
2020/07/16 Python
python如何支持并发方法详解
2020/07/25 Python
关于python3.7安装matplotlib始终无法成功的问题的解决
2020/07/28 Python
Opencv常见图像格式Data Type及代码实例
2020/11/02 Python
纯css3无js实现的Android Logo(有简单动画)
2013/01/21 HTML / CSS
酒店总经理岗位职责范本
2014/08/08 职场文书
中秋节国旗下演讲稿
2014/09/05 职场文书
购房公证委托书(2014版)
2014/09/12 职场文书
法人授权委托书公证范本
2014/09/14 职场文书
2014年财务部工作总结
2014/11/11 职场文书
2016年学校爱国卫生月活动总结
2016/04/06 职场文书
python 如何将两个实数矩阵合并为一个复数矩阵
2021/05/19 Python