MDN鎮(zhèn)文
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
手寫(xiě)實(shí)現(xiàn)reduce
實(shí)現(xiàn)方式一
Array.prototype.reduce = function (fn, init) {
if (typeof fn !== 'function') {
throw new TypeError('xxx');
}
initArr = this;
arr = initArr.concat();
if (init) arr.unshift(init);
let index, newVal;
while (arr.length > 1) {
index = initArr.length - arr.length + 1;
newVal = fn.call(null, arr[0], arr[1], index, initArr);
arr.splice(0, 2, newVal)
}
return newVal
}
實(shí)現(xiàn)方式二 (遞歸)
const reduceHelper = (fn, acc, idx, array) => {
if (array.length === 0) return acc
const [head, ...tail] = array
idx++
return reduceHelper(fn, fn(acc, head, idx, array), idx, tail)
}
Array.prototype.myReduce = function (cb, initialValue) {
const array = this
const [head, ...tail] = array
const startIndex = initialValue ? -1 : 0
return initialValue ? reduceHelper(cb, initialValue, startIndex, array) : reduceHelper(cb, head, startIndex, tail)
}
應(yīng)用場(chǎng)景
一: 累加
const sum = arr => arr.reduce((acc, val) => acc + val, 0);
sum([1, 2, 3]);
二: 計(jì)數(shù)器
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
let nameNum = names.reduce((pre, cur) => {
if (cur in pre) {
pre[cur]++
} else {
pre[cur] = 1
}
return pre
}, {})
console.log(nameNum); // //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
三: 數(shù)組扁平化
const deepFlatten = arr =>
arr.reduce((a, v) => a.concat(Array.isArray(v) ? deepFlatten(v) : v), []);
console.log(deepFlatten([1, [2, [3, 4, [5, 6]]]]));
四: 生成斐波那契數(shù)列
const fibonacci = n => Array(n).fill(0).reduce((acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i), []);
console.log(fibonacci(5));
五: 中間件
redux中經(jīng)典的compose函數(shù)中運(yùn)用了這種方式, 通過(guò)對(duì)中間件的重重層疊, 在真正發(fā)起action的時(shí)候觸發(fā)函數(shù)執(zhí)行.
const dispatch = action => {
console.log('action', action);
return action;
}
const middleware1 = dispatch => {
return action => {
console.log("middleware1");
const result = dispatch(action);
console.log("after middleware1");
return result;
}
}
const middleware2 = dispatch => {
return action => {
console.log("middleware2");
const result = dispatch(action);
console.log("after middleware2");
return result;
}
}
const middleware3 = dispatch => {
return action => {
console.log("middleware3");
const result = dispatch(action);
console.log("after middleware3");
return result;
}
}
const compose = middlewares => middlewares.reduce((a, b) => {
return function (args) {
return a(b(args))
}
})
const middlewares = [middleware1, middleware2, middleware3];
const afterDispatch = compose(middlewares)(dispatch);
// const afterDispatch = middleware1(middleware2(middleware3(dispatch)));
const testAction = arg => {
return { type: "TEST_ACTION", params: arg };
};
afterDispatch(testAction("1111"));
六: 對(duì)象空值判斷
let school = {
name: 'Hope middle school',
created: '2001',
classes: [
{
name: '三年二班',
teachers: [
{ name: '張二蛋', age: 26, sex: '男', actor: '班主任' },
{ name: '王小妞', age: 23, sex: '女', actor: '英語(yǔ)老師' }
]
},
{
name: '明星班',
teachers: [
{ name: '歐陽(yáng)娜娜', age: 29, sex: '女', actor: '班主任' },
{ name: '李易峰', age: 28, sex: '男', actor: '體育老師' },
{ name: '楊冪', age: 111, sex: '女', actor: '藝術(shù)老師' }
]
}
]
};
// 常規(guī)做法
school.classes &&
school.classes[0] &&
school.classes[0].teachers &&
school.classes[0].teachers[0] &&
school.classes[0].teachers[0].name
// reduce方法
const get = (p, o) => p.reduce((xs, x) => (xs && xs[x] ? xs[x] : null), o);
get(['classes', 0, 'teachers', 0, 'name'], school); // 張二蛋
七: 過(guò)濾屬性
根據(jù)給出的鍵值來(lái)遍歷易阳,比較對(duì)象中是否存在相同鍵值的的值,然后通過(guò)逗號(hào)表達(dá)式把賦值后的對(duì)象賦給下一個(gè)的初始值
const pick = (obj, arr) =>
arr.reduce(function (acc, curr) {
if (curr in obj) {
acc[curr] = obj[curr]
return acc;
}
}, {});
// 也可以簡(jiǎn)寫(xiě)成
const pick2 = (obj, arr) =>
arr.reduce((acc, curr) => (curr in obj && (acc[curr] = obj[curr]), acc), {});
pick({ a: 1, b: '2', c: 3 }, ['a', 'c']);
八: 分組
首先通過(guò)map計(jì)算出所有的鍵值巍杈,然后再根據(jù)建值進(jìn)行歸類(lèi)
const groupBy = (arr, func) =>
arr.map(typeof func === 'function' ? func : val => val[func])
.reduce((acc, val, i) => {
acc[val] = (acc[val] || []).concat(arr[i]);
return acc;
}, {});
groupBy([6.1, 4.2, 6.3], Math.floor);
groupBy(['one', 'two', 'three'], 'length');
九: 數(shù)組刪除指定位置的值
首先根據(jù)filter函數(shù)過(guò)濾出數(shù)組中符合條件的值坪稽,然后使用reduce在原數(shù)組中刪除符合條件的值曼玩,可以得出最后arr的值變成了[1, 3]
const remove = (arr, fn) =>{
return arr.filter(fn).reduce((acc, cur) => {
arr.splice(arr.indexOf(cur), 1);
return acc.concat(cur);
}, []);
}
const arr = [1, 7, 3, 4, 8];
console.log(remove(arr, n => n % 3 == 1))
console.log(arr)
十: 字母游戲
reduce負(fù)責(zé)篩選出每一次執(zhí)行的首字母,遞歸負(fù)責(zé)對(duì)剩下字母的排列組合窒百。
const anagrams = str => {
if (str.length <= 2) {
return str.length === 2 ? [str, str[1] + str[0]] : str;
}
return str.split("").reduce((acc, letter, i) => {
return acc.concat(anagrams(str.slice(0, i) + str.slice(i + 1)).map(val => letter + val));
}, []);
}
anagrams("abc");
十一: 排序
const orderBy = (arr, props, orders) =>
[...arr].sort((a, b) =>
props.reduce((acc, prop, i) => {
if (acc === 0) {
const [p1, p2] = orders && orders[i] === 'desc' ? [b[prop], a[prop]] : [a[prop], b[prop]];
acc = p1 > p2 ? 1 : p1 < p2 ? -1 : 0;
}
return acc;
}, 0)
);
const users = [{ name: 'fred', age: 48 }, { name: 'barney', age: 36 }, { name: 'fly', age: 26 }];
console.log(orderBy(users, ['age'], ['desc']));