JS Array.reduce 實現 Array.map 和 Array.filter
繼上一篇 ofollow,noindex">Array.prototype.reduce 後,我立志要好好學習。琢磨了很久,再加上最近看了幾篇"JS 函數語言程式設計"的文章和書籍後,然後有感而發寫下了這篇文章。
Array.prototype.map
方法相信大家都用的很熟悉了,同時我也相信很多人已經自己實現了 map
函式。沒有實現過自己的 map
? 沒關係,我們先用 for
迴圈來實現下。
Array.prototype.selfMap = function () { const ary = this const result = [] const [ fn, thisArg ] = [].slice.call(arguments) if (typeof fn !== 'function') { throw new TypeError(fn + 'is not a function') } for (let i = 0; i < ary.length; i++) { result.push(fn.call(thisArg, ary[i], i, ary)) } return result } const a = new Array(1, 2, 3, 4) a.selfMap(item => item + 1) // [ 2, 3, 4, 5 ] 複製程式碼
實現了自己的 map
,還不是美滋滋。
但是,這和本文沒有半點關係,因為我是要用 reduce
實現 map
啊
眾所周知, map
函式需要傳一個函式的,還有一個可選的 this
引數,但是我發現第二個引數大家很少用到,也不怎麼注意,我也是這樣。
[1, 2, 3].map(function(item) { console.log(this) return item }, { msg: 'mapping' }) 複製程式碼
上面:point_up_2:這段程式碼塊不僅會返回一個新的陣列,還會在控制檯列印三次
{ msg: 'mapping' } 複製程式碼
有圖有真相:point_down:

可能有的小夥伴在驗證我上面的例子時,會使用 箭頭函式
,然後發現總是列印 window
,就是下面這樣:point_down:

然後心裡暗道“無恥小兒,竟敢騙我”。心裡苦啊,箭頭函式在宣告時就綁定了它外層的this(此例的 this
為 window
,而且還改變不了, 也就是說 { msg: 'mapping' }
相當於白傳了):sob:
似乎廢話有點多額,那我們先用 reduce
來實現 map
吧(預設執行環境支援 Array.prototype.reduce
,如果不支援的話,那還寫個:hammer:)
// 這次不把方法寫在Array的原型上 const reduceMap = (fn, thisArg /*真想去掉thisArg這個引數*/ ) => { return (list) => { // 不怎麼願意寫下面這兩個判斷條件 if (typeof fn !== 'function') { throw new TypeError(fn + 'is not a function') } if (!Array.isArray(list)) { throw new TypeError('list must be a Array') } if (list.length === 0) return [] return list.reduce((acc, value, index) => { acc.push(fn.call(thisArg, value, index, list)) return acc }, []) } } // 來使用下怎麼樣 reduceMap(x => x + 1)([ 1, 2, 3 ]) // [ 2, 3, 4 ] const mapAry1 = reduceMap(function(item) { console.log(this) return item + 1 }, { msg: 'mapping' })([ 1, 2, 3 ]) // [ 2, 3, 4 ] // logging { msg: 'mapping' } three times 複製程式碼
:point_up_2:實現的原理相信大家應該都懂吧。
打鐵當趁熱,繼續來實現 filter
吧。
- for 迴圈實現版
Array.prototype.selfFilter = function () { const ary = this const result = [] const [ fn , thisArg ] = [].slice.call(arguments) if (typeof fn !== 'function') { throw new TypeError(fn + 'is not a function') } for (let i = 0; i < ary.length; i++) { if (fn.call(thisArg, ary[i], i, ary)) { result.push(ary[i]) } } return result } const a = new Array(1, 2, 3) a.selfFilter(item => item % 2 === 0) // [ 2 ] a.selfFilter(function (item) { console.log(this) return item % 2 === 0 }) // [ 2 ] // logging {} three times 複製程式碼
- reduce 實現版
// 同map, 不定義在Array的原型上 const reduceFilter = (fn, thisAry /* thisAry知不知你好討厭啊 */ )=> { return (list) => { if (typeof fn !== 'function') { throw new TypeError(fn + 'is not a function') } if (!Array.isArray(list)) { throw new TypeError('list must be a Array') } if (list.length === 0) return [] return list.reduce((acc, value, index) => { fn.call(thisAry, value, index, list) ? acc.push(value) : null return acc }, []) } } reduceFilter(x => x % 2 === 0)([ 1, 2, 3 ]) // [ 2 ] 複製程式碼
文章裡摻雜了些許 函數語言程式設計 裡面的東西,因為我也才開始學函數語言程式設計不久,就不在大佬們面前獻醜了。如果文章裡有哪裡寫的不對或者不夠準確,亦或者是覺得有寫的不好的地方,煩請各位指正,也讓我改正。