reduce方法高級使用

前端小夥伴兒應該都聽過reduce這個數組的方法,總結一下我在開發過程當中遇到的reduce的一些好玩兒的用法前端

老規矩,上MDN:reduce-MDN數組

簡單介紹一下一些重要的點koa

定義:reduce() 方法對數組中的每一個元素執行一個由您提供的 reducer 函數(升序執行),將其結果彙總爲單個返回值。異步

示例:async

const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15

reducer 函數接收4個參數:函數

Accumulator (acc) (累計器)
CurrentValue (cur) (當前值)
CurrentIndex (idx) (當前索引)
SourceArray (src) (源數組)

您的 reducer 函數的返回值分配給累計器,該返回值在數組的每一個迭代中被記住,並最後成爲最終的單個結果值this

arr.reduce(callback(accumulator, currentValue, index, array), initialValue)

callback執行數組中每一個值 (若是沒有提供 initialValue則第一個值除外)的函數,包含四個參數:spa

`accumulator`:累計器累計回調的返回值; 它是上一次調用回調時返回的累積值,或`initialValue`。

`currentValue`:數組中正在處理的元素。

`index`(可選):數組中正在處理的當前元素的索引。 若是提供了`initialValue`,則起始索引號爲0,不然從索引1起始。

`array`(可選):調用`reduce()`的數組

reduce爲數組中的每個元素依次執行callback函數,不包括數組中被刪除或從未被賦值的元素,接受四個參數:code

  • accumulator 累計器
  • currentValue 當前值
  • currentIndex 當前索引
  • array 數組

回調函數第一次執行時,accumulatorcurrentValue的取值有兩種狀況:
一、若是調用reduce()時提供了initialValueaccumulator取值爲initialValuecurrentValue取數組中的第一個值;
二、若是沒有提供 initialValue,那麼accumulator取數組中的第一個值,currentValue取數組中的第二個值。csrf

注意:官方推薦在reduce使用時提供 initialValue,爲了不錯誤,更多的詳細理解請查閱MDN,下面就用實際的例子來玩兒一下

一、基礎的累加累乘

var  arr = [1, 2, 3, 4];
var sum = arr.reduce((prev, cur) => prev + cur, 0)
var mul = arr.reduce((prev, cur) => prev * cur, 1)
console.log(sum); //    10
console.log(mul); //    24

二、對象內的操做

var result = [
    {
        subject: 'math',
        score: 10
    },
    {
        subject: 'chinese',
        score: 20
    },
    {
        subject: 'english',
        score: 30
    }
];

var sum = result.reduce((prev, cur) => {
    return cur.score + prev;
}, 0);
console.log(sum) //60

三、統計數組中元素出現次數

let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];

let nameNum = names.reduce((prev, cur)=>{
  if(cur in prev){
    prev[cur]++
  }else{
    prev[cur] = 1 
  }
  return pre
}, {})
console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}

四、數組去重

let arr = [1,2,3,4,4,1]
let newArr = arr.reduce((prev, cur)=>{
    if(!prev.includes(cur)){
      return prev.concat(cur)
    }else{
      return prev
    }
}, [])
console.log(newArr);// [1, 2, 3, 4]

五、多維數組降一維數組

let arr = [[0, 1], [2, 3], [4,[5,6,7]]]
const newArr = function(arr){
   return arr.reduce((prev, cur) => prev.concat(Array.isArray(cur) ? newArr(cur) : cur), [])
}
console.log(newArr(arr)); //[0, 1, 2, 3, 4, 5, 6, 7]

六、數組和對象深克隆

const deepClone = param => {
    if (typeof param !== 'object') return
    if (Array.isArray(param)) {
        param.reduce((prev, cur) => (cur instanceof Array ? [...prev, deepClone(cur)] : [...prev, cur]), [])
    } else {
        Object.entries(param).reduce(
            (prev, [key, value]) => (typeof value === 'object' ? { ...prev, [key]: deepClone(value) } : { ...prev, [key]: value }),
            {}
        )
    }
    return param
}

七、封裝一個同步順序執行函數,並返回結果

let fn1 = () => {
    return {
        name: 'lsd',
        age: 18
    }
}
let fn2 = () => {
    return {
        name: 'lbb',
        age: 19
    }
}
let fn3 = () => {
    return {
        name: 'whh',
        age: 20
    }
}

let fnlist = [fn1, fn2, fn3]

let res = fnlist.reduce((prev, cur) => {
    let t = cur()
    if (t) {
        prev.push(t)
    }
    return prev
}, [])
console.log(res)

八、基於7封裝異步請求順序執行,並處理請求結果

let fn1 = () => {
    return new Promise((resolve, reject) => resolve(1))
}
let fn2 = () => {
    return new Promise((resolve, reject) => reject())
}
let fn3 = () => {
    return new Promise((resolve, reject) => resolve(2))
}
let fnlist = [fn1, fn2, fn3]
 let res = fnlist.reduce((prev, cur) => {
    cur().then(
        data => {
            if (data) {
                prev.push(data)
            }
        },
        reason => {
            prev.push('失敗')
        }
    )
    return prev
}, [])
console.log(res)
// 應該在then函數中定義onResolve和onRejct函數,若是使用catch捕獲錯誤,會進入下一次事件循環,不是同步執行;此處若是須要異步執行,請自行修改

九、模擬koa洋蔥模型

// 每一箇中間件都能接收到core
function receiveMiddleware(middlewareList) {
    //將中間件隊列改造爲函數層層嵌套形式
    //[a,b,c,d] => a(b(c(d(core)))) By reduce
    let tiggerPipe = middlewareList.reduce((a, b) => core => a(b(core)))

    let tiggerPipeWitchCore = tiggerPipe(() => {
        console.log('我是核心操做')
    })

    return tiggerPipeWitchCore
}
const VerfiyCsrfToekn = next => lastMDarg => {
    console.log('驗證csrf Token')

    next(lastMDarg)

    console.log('驗證csrf Token end')
}

const VerfiyAuth = next => lastMDarg => {
    console.log('驗證是否登陸')

    next(lastMDarg)

    console.log('驗證是否登陸 end')
}

const VerfiyRoutes = next => lastMDarg => {
    console.log('驗證路由匹配')

    next(lastMDarg)

    console.log('驗證路由匹配 end')
}
let dispatch = receiveMiddleware([VerfiyCsrfToekn, VerfiyAuth, VerfiyRoutes])
dispatch()

十、帶異步控制的中間件

const store = {
    status: { name: '固態空氣' },
    getState: () => {
        return this.status
    },
    dispatch: arg => {
        console.log(`我是核心操做,參數=${arg}`)
    }
}

function receiveMiddleware(middlewareList) {
    //拿到中間件隊列
    let dispatch = store.dispatch
    let middlewareAPI = {
        dispatch: arg => {
            dispatch(arg)
        },
        getState: store.getState
    }

    //判斷中間件數量
    if (middlewareList.length === 0) {
        return dispatch
    }
    //將核心操做看成參數賦予每一箇中間件
    middlewareList = middlewareList.map(middleware => middleware(middlewareAPI))
    //將中間件隊列改造爲函數層層嵌套形式
    //[a,b,c,d] => a(b(c(d(core)))) By reduce
    let tiggerPipe = middlewareList.reduce((prev, cur) => reallyDispatch => prev(cur(reallyDispatch)))

    //重寫dispatch
    dispatch = tiggerPipe(store.dispatch)
    return dispatch
}

const VerfiyCsrfToekn = middlewareAPI => next => lastMDarg => {
    console.log('驗證csrf Token')
    next(lastMDarg)
    console.log('驗證csrf Token end')
}

const VerfiyAuth = middlewareAPI => next => lastMDarg => {
    console.log('驗證是否登陸')
    next(lastMDarg)
    console.log('驗證是否登陸 end')
}

const VerfiyRoutes = middlewareAPI => next => lastMDarg => {
    console.log('驗證路由匹配')
    next(lastMDarg)
    console.log('驗證路由匹配 end')
}

const asyncMiddleware = middlewareAPI => next => lastMDarg => {
    console.log('異步中間件-start')
    if (typeof lastMDarg === 'function') {
        lastMDarg(middlewareAPI)
    } else {
        next(lastMDarg)
        console.log('異步中間件-end')
    }
}

let dispatch = receiveMiddleware([VerfiyCsrfToekn, VerfiyAuth, VerfiyRoutes, asyncMiddleware])

let asyncFun = middlewareAPI => {
    setTimeout(() => {
        let test = '我是固態空氣'
        middlewareAPI.dispatch(test)
        console.log(middlewareAPI.getState())
    }, 3000)
}

dispatch(asyncFun)
相關文章
相關標籤/搜索