几个关于js数组方法reduce的经典片段

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

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

理解reduce函数

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

arr.reduce([callback, initialValue])

关于reduce的用法,这里不再做多述,可以去这里查看

看如下例子:

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负责筛选出每一次执行的首字母,递归负责对剩下字母的排列组合。

See the Pen reduce anagrams by 糊一笑 (@rynxiao) on CodePen.

片段二:累加器

const sum = arr => arr.reduce((acc, val) => acc + val, 0);
sum([1, 2, 3]);

See the Pen reduce sum by 糊一笑 (@rynxiao) on CodePen.

片段三:计数器

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,同时将加上之后的结果作为下次的初始值。

See the Pen reduce count occurrences by 糊一笑 (@rynxiao) on CodePen.

片段四:函数柯里化

函数柯里化的目的就是为了储存数据,然后在最后一步执行。深入了解,请参看小火柴的这篇文章http://www.cnblogs.com/xiaohuochai/p/8026074.html

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(当然也可以自己指定),如果所传的参数比当前参数少,则继续递归下面,同时储存上一次传递的参数。

See the Pen reduce curry by 糊一笑 (@rynxiao) on CodePen.

片段五:数组扁平化

const deepFlatten = arr =>
  arr.reduce((a, v) => a.concat(Array.isArray(v) ? deepFlatten(v) : v), []);
deepFlatten([1, [2, [3, 4, [5, 6]]]]);

See the Pen reduce deep flatten array by 糊一笑 (@rynxiao) on CodePen.

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

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

See the Pen reduce fibonacci by 糊一笑 (@rynxiao) on CodePen.

片段七:管道加工器

const pipe = (...funcs) => arg => funcs.reduce((acc, func) => func(acc), arg);
pipe(btoa, x => x.toUpperCase())("Test");

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

See the Pen reduce pipe by 糊一笑 (@rynxiao) on CodePen.

片段八:中间件

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的时候触发函数执行。

See the Pen reduce middlewares by 糊一笑 (@rynxiao) on CodePen.

片段九: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);
}

See the Pen reduce handleActions by 糊一笑 (@rynxiao) on CodePen.

片段十:数据加工器

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);

See the Pen reduce handleActions by 糊一笑 (@rynxiao) on CodePen.

片段十一:对象空值判断

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);   // 张二蛋

See the Pen reduce handleActions by 糊一笑 (@rynxiao) on CodePen.

片段十二:分组

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计算出所有的键值,然后再根据建值进行归类

See the Pen reduce group-by by 糊一笑 (@rynxiao) on CodePen.

片段十三:对象过滤

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']);

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

See the Pen reduce pick by 糊一笑 (@rynxiao) on CodePen.

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

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]

See the Pen reduce remove by 糊一笑 (@rynxiao) on CodePen.

片段十五: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')]);

See the Pen reduce runPromisesInSeries by 糊一笑 (@rynxiao) on CodePen.

片段十六:排序


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']);

See the Pen reduce orderBy by 糊一笑 (@rynxiao) on CodePen.

片段十七:选择

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');

See the Pen reduce select by 糊一笑 (@rynxiao) on CodePen.

参考地址

https://zhuanlan.zhihu.com/p/27748589

http://www.jb51.net/article/121572.html

Https://github.com/Chalarangelo/30-seconds-of-code#anagrams-of-string-with-duplicates

原文地址:https://www.cnblogs.com/rynxiao/p/8195010.html

时间: 2024-10-09 23:38:03

几个关于js数组方法reduce的经典片段的相关文章

php数组以及js数组方法整理

在js中数组非常经常用到,熟练掌握数组的方法能够大大的提高对自己的变成效率,最近解除php,学得非常皮毛,遇到一个问题,自己一直陷入foreach循环如何解决的死循环中.结果一直没能很好的解决,回来讨教了一下同学,更加觉得数组的一些方法很好用,所以有必要整理一下数组的一些方法,希望自己能牢记它们. 一,js数组的操作方法: 参照w3c内容:http://www.jb51.net/w3school/js/jsref_obj_array.htm 以及<javascript权威指南>和<jQu

js 数组方法总结

Array数组: length属性 可通过array.length增加或者减少数组的长度,如;array.length=4(数组长3,第四位为undefined),也可单纯获得长度.array[array.length]=''赋值. 检测数组 检测是否数组ES3  instanceof array  ES5新增的Array.isArray(),支持的IE9+,Opera 10.5+,Chrome,Safari5+. 一:原数组不变  [,start],表示0或1个参数 concat() 无参,返

JS数组方法汇总 array数组元素的添加和删除

js数组元素的添加和删除一直比较迷惑,今天终于找到详细说明的资料了,先给个我测试的代码^-^ var arr = new Array(); arr[0] = "aaa"; arr[1] = "bbb"; arr[2] = "ccc"; //alert(arr.length);//3 arr.pop(); //alert(arr.length);//2 //alert(arr[arr.length-1]);//bbb arr.pop(); //al

JS数组方法汇总 array数组元素的添加和删除 - yuzhongwusan - 博客园

body { font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI",Tahoma,Helvetica,Sans-Serif,"Microsoft YaHei", Georgia,Helvetica,Arial,sans-serif,宋体, PMingLiU,serif; font-size: 10.5pt; line-height: 1.5;

JavaScript数组方法--reduce、reduceRIght、reverse

今天写的reduce是比较复杂的一个数组方法,其实在这之前我也用过reduce,可是每次用起来总感觉不那么顺手,主要还是因为不熟,对reduce本身不熟.首先reduce这个单词翻译为中文,不那么直观,再加上他的示例比较简单,导致用在复杂情况下,就有点懵逼的感觉.通过自己的理解,我们重构一次,可能更能够方便理解! reduce:reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值.看到MDN给的这句解释,可能就懵了!什么叫reduce

js数组方法扩展

/** * Created by Administrator on 2016/9/1. */ //数组去重 Array.prototype.unique = function(){ this.sort(); var re=[this[0]]; for(var i = 1; i < this.length; i++){ if( this[i] !== re[re.length-1]){ re.push(this[i]); } } return re; } //扩展数组方法:查找指定元素的下标 Ar

JS数组方法的的返回值和是否改变该数组总结

concat() 方法 concat() 方法用于连接两个或多个数组. 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本. 返回值 返回一个新的数组.该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的.如果要进行 concat() 操作的参数是数组,那么添加的是数组中的元素,而不是数组. join() 方法  不改变原数组 join() 方法用于把数组中的所有元素放入一个字符串. 元素是通过指定的分隔符进行分隔的. 返回值 返回一个字符串.该字符串是通过把

js数组方法整理

整理了以下数组方法 join() push()和pop() shift() 和 unshift() sort() reverse() concat() slice() splice() indexOf()和 lastIndexOf() (ES5新增) forEach() (ES5新增) map() (ES5新增) filter() (ES5新增) every() (ES5新增) some() (ES5新增) 1.join() join,就是把数组转换成字符串,然后给他规定个连接字符,默认的是逗号

天总结一下常用的JS数组方法

1.map :遍历数组的每一项并对其进行操作.  有返回值  且  不改变原数组. var arr = [1, 2, 3, 4, 5, 6]; var res = arr.map(item => { return item * 2; }); console.log(arr); //[1, 2, 3, 4, 5, 6] console.log(res); //[2, 4, 6, 8, 10, 12] 2. forEach :遍历数组每一项并可对其操作,但是结果无用功.  因为forEach没有返回