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 相关文章推荐
初窥JQuery(一)jquery选择符 必备知识点
Nov 25 Javascript
精心挑选的15个jQuery下拉菜单制作教程
Jun 15 Javascript
jQuery mobile类库使用时加载导航历史的方法简介
Dec 04 Javascript
jQuery CSS3相结合实现时钟插件
Jan 08 Javascript
Node.js服务器环境下使用Mock.js拦截AJAX请求的教程
May 23 Javascript
JavaScript知识点总结(四)之逻辑OR运算符详解
May 31 Javascript
Vue.js组件tree实现省市多级联动
Dec 02 Javascript
AngularJs篇:使用AngularJs打造一个简易权限系统的实现代码
Dec 26 Javascript
vue+iview写个弹框的示例代码
Dec 05 Javascript
js前端如何写一个精确的倒计时代码
Oct 25 Javascript
解决vue admin element noCache设置无效的问题
Nov 12 Javascript
js实现弹窗效果
Aug 09 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
新浪微博API开发简介之用户授权(PHP基础篇)
2011/09/25 PHP
优化WordPress中文章与评论的时间显示
2016/01/12 PHP
Ajax中的JSON格式与php传输过程全面解析
2017/11/14 PHP
NodeJS 模块开发及发布详解分享
2012/03/07 NodeJs
JS实现随机数生成算法示例代码
2013/08/08 Javascript
js中window.open()的所有参数详细解析
2014/01/09 Javascript
Javascript核心读书有感之类型、值和变量
2015/02/11 Javascript
javascript实现设置、获取和删除Cookie的方法
2015/06/01 Javascript
使用requestAnimationFrame实现js动画性能好
2015/08/06 Javascript
Function.prototype.apply()与Function.prototype.call()小结
2016/04/27 Javascript
浅谈jquery上下滑动的注意事项
2016/10/13 Javascript
写jQuery插件时的注意点
2017/02/20 Javascript
Vue.js实现输入框绑定的实例代码
2017/08/24 Javascript
浅析Javascript中双等号(==)隐性转换机制
2017/10/27 Javascript
js判断传入时间和当前时间大小实例(超简单)
2018/01/11 Javascript
vuejs实现标签选项卡动态更改css样式的方法
2018/05/31 Javascript
详解在React中跨组件分发状态的三种方法
2018/08/09 Javascript
js防抖和节流的深入讲解
2018/12/06 Javascript
iview实现select tree树形下拉框的示例代码
2018/12/21 Javascript
Vue 组件注册实例详解
2019/02/23 Javascript
详解原生JS回到顶部
2019/03/25 Javascript
说说如何使用Vuex进行状态管理(小结)
2019/04/14 Javascript
微信小程序中weui用法解析
2019/10/21 Javascript
vue中选中多个选项并且改变选中的样式的实例代码
2020/09/16 Javascript
解决Vue keep-alive 调用 $destory() 页面不再被缓存的情况
2020/10/30 Javascript
Python RuntimeError: thread.__init__() not called解决方法
2015/04/28 Python
python通过定义一个类实例作为ftp回调方法
2015/05/04 Python
Python实现的单向循环链表功能示例
2017/11/10 Python
PyQt 实现使窗口中的元素跟随窗口大小的变化而变化
2019/06/18 Python
python将邻接矩阵输出成图的实现
2019/11/21 Python
pandas 强制类型转换 df.astype实例
2020/04/09 Python
python基于win32api实现键盘输入
2020/12/09 Python
珠宝的促销活动方案
2014/08/31 职场文书
集结号观后感
2015/06/08 职场文书
vue-element-admin项目导入和导出的实现
2021/05/21 Vue.js
python之np.argmax()及对axis=0或者1的理解
2021/06/02 Python