原文中部分源碼來源於:JS Array.reduce 實現 Array.map 和 Array.filter
Array 中的高階函數 ---- map, filter, reduce
map() - 映射
var newArr = array.map((currentValue, index, array) => { return ... }, thisValue);
- currentValue, 必須,當前的元素值;
- index, 可選,當前元素值的索引;
- array, 可選,原數組;
- thisValue, 可選,對象作為該執行回調時使用,傳遞給函數,用作 "this" 的值;
- return 新數組;
栗子:
var array1 = [1,4,9,16]; const map1 = array1.map(x => x *2); console.log(array1); // [1,4,9,16] console.log(map1); // [2,8,18,32]
注意:
- map() 不會對空數組進行檢測;
filter() - 過濾,篩選
var newArr = array.filter((currentValue, index, array) => { return ... }, thisValue);
- currentValue, 必須,當前的元素值;
- index, 可選,當前元素值的索引;
- array, 可選,原數組;
- thisValue, 可選,對象作為該執行回調時使用,傳遞給函數,用作 "this" 的值;
- return 新數組;
栗子:過濾不符合項
var arr = [20,30,50, 96,50] var newArr = arr.filter(item => item>40) console.log(arr) // [20,30,50, 96,50] console.log(newArr) // [50, 96, 50]
高頻用途:
- 上例中的過濾不符合項;
- 去掉數組中的 空字符串、0、undefined、null;
var arr = ['1', '2', null, '3.jpg', null, 0] var newArr = arr.filter(item => item) // 也可以寫成 // var newArr = arr.filter(Boolean); console.log(newArr) // ["1", "2", "3.jpg"]
- 數組去重;
注意:
- filter() 不會對空數組進行檢測;
reduce - 累計
var result = array.reduce((total, currentValue, currentIndex, array) => { return ... }, initialValue);
- total, 必須,初始值,第一次循環之后是計算后的返回值;
- currentValue, 必須,當前的元素值;
- currentIndex, 可選,當前元素值的索引;
- array, 可選,原數組;
- initialValue, 可選,傳遞給函數的初始值,即此值會在第一次循環之前賦值給 total;
- return 經過處理過的 total;
栗子:統計字符串中每個字符出現的次數
const str = '9kFZTQLbUWOjurz9IKRdeg28rYxULHWDUrIHxCY6tnHleoJ'
const obj = {}
Array.from(str).reduce((accumulator, current) => {
current in accumulator ? accumulator[current]++ : accumulator[current] = 1
return accumulator;
}, obj)
當然,非 reduce 的寫法是:
const str = '9kFZTQLbUWOjurz9IKRdeg28rYxULHWDUrIHxCY6tnHleoJ'
const obj = {}
str.split('').forEach(item => {
obj[item] ? obj[item]++ : obj[item] = 1
})
reduce 的用途很廣泛,可以說,js 中有關數組循環的模塊都可以使用 reduce 來實現,這里不一一列舉,詳見 reduce-MDN
js 實現 map
原生 js 實現:
Array.prototype.myMap = function(fn, context = window) {
if (typeof fn !== 'function') return;
let newArr = [];
for(let i = 0, len = this.length; i < len; i++) {
newArr.push(fn.call(context, this[i], i, this))
}
return newArr;
}
// 使用
[1,2,3].myMap(function(v, i, arr) {
console.log(v, i, arr);
return v * 2;
})
有一點奇怪的是,需要先在 Array 上掛 myMap() 這個方法,然后回車后才能使用,如果將上述代碼全部復制進瀏覽器控制台,回車運行會報錯,這是為什么?
使用 reduce 實現:
Array.prototype.reduceMap = function(fn, context = window) {
if (typeof fn !== 'function') return;
// or if (typeof fn !== 'function') throw new TypeError(fn + 'is not a function') ;
let _this = this;
let newArr = _this.reduce(function(total, cV, cI, _this) {
return total.concat([fn.call(context, cV, cI, _this)])
}, [])
return newArr
}
上面的示例是掛載在 Array 上的,下面這個示例是函數式編程示例:
let fpReduceMap = (fn, context = window) => {
return targetArr => {
if (typeof fn !== 'function') throw new TypeError(fn + 'is not a function')
if (!Array.isArray(targetArr)) throw new TypeError('targetArr must be a Array')
if (targetArr.length == 0) return [];
return targetArr.reduce((total, cV, cI, targetArr) => {
return total.concat([fn.call(context, cV, cI, targetArr)])
}, [])
}
}
// 使用
fpReduceMap(function(v) {
console.log(this);
return v + 1;
}, {msg: 'mapping'})([1,2,3])
