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.pswp.cn/news/260006.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/260006.shtml
英文地址,請注明出處:http://en.pswp.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上執行…