reduce
是ES5中新引入的一个API。javascript
假如你还不知道reduce的用法,请先阅读下MDN文档中关于reduce的介绍。(不得不说,MDN文档太强大了,里面列举了不少有用的方法)java
本文将介绍借助reduce函数,利用其可以遍历到数组的每个元素,而且次遍历均可以使用上次遍历结果的特性,实现的一些功能。编程
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
复制代码
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
复制代码
当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 ]
复制代码
map
函数接收一个函数做为参数,做为参数的函数接收三个参数值,分别是遍历数组的每一项元素,元素的索引和数组自己。这三个参数恰好和reduce
函数接收的第一个函数参数的第二、三、4个参数是对应的。函数
实现思路是,将每次遍历的元素,做为传入的函数的参数,并将函数执行的结果放入新的数组中。ui
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 ]
复制代码
实现filter
的思路和实现map
是一致的,只不事后者是一股脑的把执行结果全放入数组中,而filter
须要作一个判断:若是filter
函数传入的参数(参数是一个函数)执行后有返回值,即通过了检验,才将遍历的当前元素放入数组中,若是没有返回值,就忽略。this
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 ]
复制代码
compose
是函数式编程的核心思想,简单说就是将若干个函数组合成一个函数来执行,而且每一个函数执行的结果都能做为下一个函数的参数。这也是使用reduce
实现compose
的思路。spa
假设有两个函数,做用分别是将字符串转为大写,在字符串末尾追加感叹号:prototype
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)
}
}
复制代码
数组扁平化,针对的是多维数组,将其扁平、展开,成为一维数组。
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
还有更多种神奇的应用,等待着各位小伙伴的发现和使用。