你應該知道的JS: reduce的n種應用
reduce
是ES5中新引入的一個API。
假如你還不知道reduce的用法,請先閱讀下MDN文件中關於reduce的介紹。(不得不說,MDN文件太強大了,裡面列舉了很多有用的方法)
本文將介紹藉助reduce函式,利用其能夠遍歷到陣列的每一個元素,並且次遍歷都可以使用上次遍歷結果 的特性,實現的一些功能。
1.累和/累積
let arr = [1, 2, 3, 4, 5] console.log(arr.reduce((prev, cur) => prev + cur)) // 15 // 可以實現另類的階乘 console.log(arr.reduce((prev, cur) => prev * cur)) // 120 複製程式碼
2.求最大值/最小值
let arr = [1, 2, 3, 4, 5] console.log(arr.reduce((prev, cur) => Math.max(prev, cur))); // 5 console.log(arr.reduce((prev, cur) => Math.min(prev, cur))); // 1 複製程式碼
3. 陣列去重
當reduce
接收兩個引數時,即reduce(fn, init)
,init
將作為fn
的第一個引數prev
傳入。
這裡,將一個空陣列[]
作為去重後的新陣列,通過做判斷,如果該容器內已經存在某元素,就啥也不做;反之,如果該容器內還沒有一個元素,就將其推入容器。
let arr = [1, 2, 3, 1, 1, 2, 3, 3, 4, 3, 4, 5] let res = arr.reduce((prev, cur)=>{ !prev.includes(cur) && prev.push(cur) return prev }, []) console.log(res) // [ 1, 2, 3, 4, 5 ] 複製程式碼
4.實現map函式
map
函式接收一個函式作為引數,作為引數的函式接收三個引數值,分別是遍歷陣列的每一項元素,元素的索引和陣列本身。這三個引數剛好和reduce
函式接收的第一個函式引數的第2、3、4個引數是對應的。
實現思路是,將每次遍歷的元素,作為傳入的函式的引數,並將函式執行的結果放入新的陣列中 。
let arr = [1, 2, 3] Array.prototype._map = function(cb) { if(typeof cb === 'function') { // this: 呼叫_map方法的當前陣列物件 let arr = this; return arr.reduce((prev, item, index, array) => { prev.push(cb(item, index, array)) return prev }, []) } else { throw new Error(cb + ' is not function') } } let res = arr._map(n => n*2) console.log(res) // [ 2, 4, 6 ] 複製程式碼
5.實現filter函式
實現filter
的思路和實現map
是一致的,只不過後者是一股腦的把執行結果全放入陣列中,而filter
需要做一個判斷:
如果filter
函式傳入的引數(引數是一個函式)執行後有返回值,即經過了檢驗,才將遍歷的當前元素放入陣列中,如果沒有返回值,就忽略
。
let arr = [1, 2, 3, 4, 5]; Array.prototype._filter = function(cb) { if(typeof cb === 'function') { let arr = this; return arr.reduce((prev, item, index, array) => { cb(item, index, array) ? prev.push(item) : null return prev }, []) } else { throw new Error(cb + ' is not function') } } let res = arr._filter(n => n>2) console.log(res) // [ 3, 4, 5 ] 複製程式碼
6.實現compose
compose
是函數語言程式設計的核心思想,簡單說就是將若干個函式組合成一個函式來執行,並且每個函式執行的結果都能作為下一個函式的引數
。這也是使用reduce
實現compose
的思路。
假設有兩個函式,作用分別是將字串轉為大寫,在字串末尾追加感嘆號:
function toUpperCase(str) { return str.toUpperCase(); } function add(str) { return str += '!' } 複製程式碼
一般情況下,會這樣使用:
var str = 'hello world' var res = toUpperCase(str) res = add(res) console.log(res); // HELLO WORLD! 複製程式碼
使用compose
後,效果是這樣的,執行fn
,相當於依次執行了toUpperCase
和add
:
var fn = compose(add, toUpperCase) console.log(fn(str));// HELLO WORLD! 複製程式碼
接下來實現一下compose
:
function compose() { let args = [].slice.call(arguments) return function (x) { // 因為compose()接收的函式引數,是從右往走順次執行的, // 所以這裡使用reduceRight, 用法和reduce一致,只不過是從右往左遍歷陣列。 return args.reduceRight((prev, cur) => { return cur(prev) }, x) } } 複製程式碼
7.陣列扁平化
陣列扁平化,針對的是多維陣列,將其扁平、展開,成為一維陣列。
let arr = [1, 2, '3js', [4, 5, [6], [7, 8, [9, 10, 11], null, 'abc'], {age: 12}, [13, 14]], '[]']; function flatten(arr) { if(Array.isArray(arr)) { return arr.reduce((prev, cur) => { // 如果遍歷的當前項是陣列,再迭代展平 return Array.isArray(cur) ? prev.concat(flatten(cur)) : prev.concat(cur) }, []) } else { throw new Error(arr + ' is not array') } } console.log(flatten(arr)); 複製程式碼
結束
當然,除了以上幾種,reduce
還有更多種神奇的應用,等待著各位小夥伴的發現和使用。