有一段時間沒更新了,最近挺忙的(懶病犯了)。今天偶然想到以前去去哪兒面試的時候,面試管問個人redece題目,當時被血虐的場景。乾脆今天咱們就來聊一下redece方法以及相關的應用面試
reduce(callback,initval)
其中callback函數接收4個參數:編程
若是initval傳了,則索引從0開始,acc是initval,cur是arr[0]
若是initval沒有傳,則索引從1開始,acc是arr[0],cur是arr[1]
reducer 函數的返回值分配給累計器,該返回值在數組的每一個迭代中被記住,並最後成爲最終的單個結果值。數組
const arr = [1,2,3,4,5]; console.log(arr.reduce((pre,cur)=>{return pre+cur})) //1+2+3+4+5 15
var product = [ { name: '蘋果', count: 2, price: 5 }, { name: '桃子', count: 5, price: 2 }, { name: '西瓜', count: 1, price: 10 } ]; var total = product.reduce((pre,cur)=>{ return pre+cur.count*cur.price },0) // 30
知道了reduce的兩種模式,利用遞歸實現它並不複雜函數式編程
// callback參數有4個。pre,cur,index,arr Array.prototype.myReduce = function(callback,prev){ for(let i = 0 ; i < this.length; i++){ // 判斷有沒有第二個參數 if(!prev){ // 沒有的話複雜點,第一次拿的是兩個元素arr[0],arr[1],注意index的變化 prev = callback(this[i],this[i+1],i+1,this); //這裏的指針是i+1都是對的,可是下一次循環的時候i必須按是3因此須要+1 i++; // 第一次循環了兩個變量,下次應該從第三個執行,因此向後移動 }else{ //有的話最簡單,直接就是從arr[0]開始遞歸 prev = callback(prev,this[i],i,this); } } return prev; }
好不容易學了reduce,只計算個水果價格,是否是有點過小才大用了?
咱們看一看面試中能直接大幅度提高逼格的題目函數
相信你們都應該知道怎麼用for-in怎麼遍歷數組(字符串split出來的)並藉助一個空對象來計數
可是面試寫十幾行代碼仍是比較low並且容易出錯的
咱們看一個逼格高一點的實現this
var arrString = 'abcdaabc'; arrString.split('').reduce((res, cur)=>{ res[cur] ? res[cur] ++ : res[cur] = 1 return res; }, {})
面試官讓實現一個原生的flat方法prototype
// arr.flat(depth) 原生的語法 depth指定要提取嵌套數組的結構深度,默認是1 傳0不扁平話,傳Infinity則展開任意深度的嵌套數組 咱們先不考慮depth 怎麼用遞歸實現一版展開任意深度的flat方法 Array.prototype.myFlat = function(){ return this.reduce((pre,cur)=>{ if(Array.isArray(cur)){ //是個數組再遞歸展開一層並鏈接 pre = [...pre,...cur.myFlat()] //必定要有一個去扁平化的操做 }else{ //不是數組就直接加入結果數組中 pre.push(cur) } return pre //注意返回的是一個數組 },[]) } var arr = [1,2,[3,[3]],4].myFlat() console.log(arr) 再加上depth進行遞歸 Array.prototype.myflat = function(depth=1) { //實際上邊界條件仍是有一點問題 return this.reduce((pre, cur) => { if (Array.isArray(cur)) { if (depth > 0) { depth-- pre = [...pre,...cur.myflat(depth)] } else { // depth = 0結束遞歸 pre.push(cur) } } else { pre.push(cur) } return pre }, []) } console.log([1, 2, [3,[5,[1]]], 4].myflat()) //[ 1, 2, 3, [ 5, [ 1 ] ], 4 ] console.log([1, 2, [3,[5,[1]]], 4].myflat(0)) //[ 1, 2, [ 3, [ 5, [ 1 ] ] ], 4 ] console.log([1, 2, [3,[5,[1]]], 4].myflat(2)) //[ 1, 2, 3, 5, [ 1 ], 4 ] console.log([1, 2, [3,[5,[1]]], 4].myflat(Infinity)) //[ 1, 2, 3, 5, 1, 4 ]
最後簡單介紹一下compose方法以及怎麼利用reduce 一行代碼實現。 這但是中間件的原理,你們仔細聽!指針
var compose = function(f,g) { //compose極簡寫法,僅作示例 return function(x){ return f(g(x)) } }
f和g都是函數,x是在他們之間經過'管道' 傳輸的值。
compose看起來就像是飼養函數,你就是飼養員。你能夠選擇多個有特色的函數,讓它們結合,產生一個嶄新的函數。
有個這個函數咱們能幹嗎呢
咱們看一個例子:
咱們如今想統計兩個字符串的總長度 並打印:總長度:xxx
通常的寫法就是寫一坨
函數式編程告訴咱們不要這樣作,這麼寫耦合性過高了,很差維護,咱們應該想搭積木同樣,拆成若果基礎方法,而後在拼接起來。 數據從這些方法組成的管道中流淌一遍出來就獲得想要的結果了。
好處就是低耦合,可組合(像不像dota裏面的卡爾,qwe三個球搭配能夠調出N多技能)
因而咱們這麼寫code
function sum(a,b){ return a+b; } function len(str){ return str.length } function addPrefix(content){ return '總長度:'+content; } console.log(addPrefix(len(sum('x-1','y-2')))) //看着怪怪的
這麼寫最後一句話真的很煩人
因而借用compose函數咱們這麼寫中間件
const newFn = compose(addPrefix,len,sum) console.log(newFn('x-1','y-2'))
那個這個compose函數的真實寫法是啥呢
我給出3種,下次有時間再細說
//利用reduceRight function compose(...fns){ return function(...args){ let lastFn = fns.pop(); return fns.reduceRight((prev,current)=>{ //[addPrefix,len,sum] return current(prev) // 每次當前函數處理得是以前函數處理得結果!!! 可是首個不同,首個就是首個函數得執行結果 },lastFn(...args)) //先得把參數傳入進來 } } //利用reduce // 遞歸規律以下 // a:addPrefix b:len // a:function(...args){return addPrefix(len(...args))} b:sum function compose(...fns){ return fns.reduce(function(a,b){ return function(...args){ return a(b(...args)) } }) } //reduce簡化版 一行代碼搞定 面試裝B必背 let compose = (...fns)=>fns.reduce((a,b)=>(...args)=>a(b(...args)));
今天的彙報就到這了,謝謝你們百忙中抽出時間閱讀,相信掌握上面reduce個個層次用例,面試這方面必定是滿滿的逼格。另外本人技術有限,若是哪寫的不對,歡迎在評論區留言指出。