一、reduce功能介绍及定义(自我理解)
- reduce方法为数组中的一个高阶函数,接受两个参数,第一个参数为回调函数,第二个为初始值。如果不给入初始值则会以数组第一项为初始值!
- reduce会循环数组每一项,并且会保留上一次循环的结果供下一次循环使用,最终结果为数组循环完毕后的最终返回(return)的值。
- 那这样咱们就可以这么理解了,给入一个初始值,后续操作都在给这个初始值做修饰!比如说给入对象最终返回对象、给入数组最终返回数组、给入字符串最终返回字符串、给入Boolean值最终返回Boolean值(true | false)…
- 再然后我们捋捋装饰器模式:允许向现有的对象添加功能,且不能影响它的构成(比如说一个人,你可以给他添加英语能力、可以给他添加法语能力,但是你不能让这个人的手没了),这么一看reduce不就是非常适合循环给对象添加功能吗?这不就是满足了装饰器模式了嘛。
二、各种使用方式
- 全网都有的最简单例子:累加递增
const arr = [1, 2, 3, 4, 5, 99]
arr.reduce((pre, next) => pre + next)
- 【模仿数组includes】简单的includes功能模仿实现(返回某值是否在数组中出现过)
const fn = () => { console.log(11) }
const obj = {}
const arr = [2, '2', fn, obj]
const selfIncludes = (arr, value) => {
try {
return arr.reduce((pre, next) => {
if (next === value) throw true
return false
}, false)
} catch (end) {
if (typeof end === 'boolean') return true;
}
}
- 【模仿数组indexOf】简单的indexOf功能模仿实现(返回最先找到值的索引,没找到则返回-1)
const fn = () => { console.log(11) }
const obj = {}
const arr = [2, '2', fn, obj]
const selfIndexOf = (arr, value) => {
try {
return arr.reduce((pre, next) => {
if (next === value) throw pre
return ++pre
}, 0) && -1
} catch (end) {
if (typeof end === 'number') return end;
}
}
console.log(selfIndexOf(arr, fn))
- 【模仿数组map】简单的map功能模仿实现(循环遍历数组最终返回处理后的值)
const fn = () => { console.log(11) }
const obj = {}
const arr = [2, '2', fn, obj]
const selfMap = (arr, fn) => {
return arr.reduce((pre, next) => {
pre.push(fn(next, pre.length))
return pre
}, [])
}
console.log(selfMap(arr, (item, i) => {
return {
name: item,
index: i
}
}))
console.log(selfMap(arr, () => {}))
console.log(arr.map(() => {}))
- 【模仿数组flat】简单的flat方法模拟实现(给数组内部子集合进行将为)(递归)
const selfFlat = (arr, deep) => {
if (deep > 0)
return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? flat(cur, deep - 1) : cur), [])
return arr.slice()
}
调用:selfFlat([1, [2], [[3], [4]], [[[5], [6]]]], 2)
结果:(6) [1, 2, 3, 4, Array(1), Array(1)]
调用:selfFlat([1, [2], [[3], [4]], [[[5], [6]]]], 3)
结果:(6) [1, 2, 3, 4, 5, 6]
调用:selfFlat([1, [2], [[3], [4]], [[[5], [6]]]], Infinity)
结果:(6) [1, 2, 3, 4, 5, 6]
- 过滤掉对象中为undefined、null、空字符串、NaN的key与值
const filterParam = (obj) => Object.entries(obj).reduce((pre, [key, value]) => {
if (value || value === 0) pre[key] = value
return pre
}, {});
console.log(filterParam({name: undefined, age: 0, class: 'ant-design', test: NaN}))
- lodash 中 keyBy 功能简单实现(具体细节不考虑)(使用数组内部每项的某个key对应的值为最终生成对象的key,数组当前项为最终生成对象的值)
const arr = [
{
name: '张三',
age: 16
},
{
name: '李四',
age: 17
},
{
name: '王五',
age: 18
},
]
const keyBy = (array, key) => {
return array.reduce((pre, next) => {
pre[next[key]] = next;
return pre;
}, {})
}
console.log(
keyBy(arr, 'name')
)
- 装饰器模式演示(创建Person这个类,添加一个zs的Person,把skillArr中的技能教给zs,最后让zs使用学习到的技能)
class Person {
skill = {
中文: (string) => {
return string;
}
}
constructor(params) {
this.info = params;
}
studySkill(skillName, skillFn) {
if (this.skill[skillName]) return '这个技能我会!';
this.skill[skillName] = skillFn;
return `${skillName}学习完成`;
}
say(string, way) {
if (!this.info.isLanguage?.includes(way)) return '你确定这是一门语言吗?';
if (!this.skill[way]) return '我不会这个语言!';
return this.skill[way](string);
}
};
const zs = new Person({
name: 'zs',
age: 18,
isLanguage: ['中文', '英语', '法语', '俄语']
});
const skillArr = {
英语: (string) => {
const end = 'Hello world';
return end;
},
法语: (string) => {
const end = 'Bonjour, le monde.';
return end;
},
中文: (string) => {
const end = '你好,世界。';
return end;
}
}
Object.entries(skillArr).reduce((pre, next) => {
const [skillName, skillFn] = next;
const sayMessage = pre.studySkill(skillName, skillFn);
console.log(sayMessage);
return pre;
}, zs);
console.log(zs);
console.log(zs.say('你好', '英语'))
console.log(zs.say('你好', '法语'))
console.log(zs.say('你好', '中文'))
console.log(zs.say('你好', '俄语'))
console.log(zs.say('你好', '鸟语'))
总结
- reduce是真的强大,数组内部的方法应该都可以用 reduce 去实现,有兴趣的小伙伴可以去试试看。
- reduce是从左往右循环执行,还有一个 reduceRight 是从右往左循环执行!
- reduce的返回值取决于设置的初始值(常规用法),但是这也不是绝对的(非常规用法)!