学习笔记—前端基础之ES6的数组

日常的学习笔记,包括 ES6、Promise、Node.js、Webpack、http 原理、Vue全家桶,后续可能还会继续更新 Typescript、Vue3 和 常见的面试题 等等。

reduce

1
2
3
4
let r = [1, 2, 3, 4, 5].reduce((total, num) => {
return total + num
})
console.log(r);

reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

reduce() 可以作为一个高阶函数,用于函数的 compose

(注:reduce() 对于空数组是不会执行回调函数的。)

简单来说,reduce 中会接受一个函数,函数的第一次循环,会将数组的前两项传入,并执行相应的计算,并将结果返回。往后的每一次循环,都会将上一次循环的结果传递到第一个参数中。

initialValue

initialValuereduce()的第二个参数,表示传递给函数的 初始值

我们可以用它来计算购物车的总价格

1
2
3
4
let r = [{price: 100, count: 1}, {price: 200, count: 2}, {price: 300, count: 3}].reduce((total, num) => {
return total + num.price * num.count
}, 0)
console.log(r); // 1400

这样我们整个数组默认的第一项就变成了 0,对于处理这种非数字数组非常好用。

currentIndex

currentIndex , reduce()函数的第三个参数,表示当前 元素的索引

我们可以用它来将多个数据合并成一个数据。

1
2
3
4
5
6
7
let keys = ['name', 'age'];
let values = ['mxs', 18];
let obj = keys.reduce((memo, cur, index) => {
memo[cur] = values[index]
return memo
}, {});
console.log(obj); // {name: 'mxs', age: 18}

模拟compose函数逻辑

compose 函数,函数调用扁平化。一个函数的运行结果当作实参传给下一个函数的这种操作,使复杂函数调用看起来更清晰。

假设我们目前需要实现这样一个功能

有两个 String 字符串,将其 拼接转换成大写 ,最后再 添加特殊字符并展示

我们可能会这样解决这个问题。

1
2
3
4
5
6
7
8
9
10
11
12
let str1 = 'mxs'
let str2 = 'nb'
function sum(a, b) {
return a + b
}
function toUpper(str) {
return str.toUpperCase()
}
function add(str) {
return '***' + str + '***'
}
console.log(add(toUpper(sum(str1, str2)))) // ***MXSNB***

我们只模拟了三种功能,整个代码就已经很繁琐了。

我们为了简化这种繁琐的代码,可以利用 compose函数 对其进行处理。

1
2
3
4
5
6
7
8
9
10
function compose(...fns) {
return function (...args) {
let fn = fns.shift();
return fns.reduce((a, b) => {
return b(a)
}, fn(...args))
}
}
let r = compose(sum, toUpper, add)(str1, str2)
console.log(r); // ***MXSNB***

我们用一个名为 compose函数 的方法进行 闭包封装 ,这样会使输出代码看起来更整洁,逻辑更清晰。

可以利用箭头函数简化 compose函数 代码

1
2
3
4
let compose = (...fns) => (...args) => {
let fn = fns.shift();
return fns.reduce((a, b) => b(a), fn(...args))
}

同时,我们还可以在实现思路上进行简化。

1
2
3
4
5
6
7
function compose(...fns) {
return fns.reduceRight((a, b) => {
return (...args) => {
return a(b(...args))
}
})
}

这种实现方式非常难理解,但是也很好解释通,私下可以花点时间看一下。

然后我们再对其写法进行简化,最终就会变成如下代码。

1
let compose = (...fns) => fns.reduceRight((a, b) => (...args) => a(b(...args)))

最终就成了一行代码。

这行代码也被应用在 redux源码 中。

手写实现reduce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Array.prototype.reduce = function (callBack, prev) {
for (let i = 0; i < this.length; i++) {
if (prev == undefined) {
prev = callBack(this[i], this[i + 1], i + 1, this);
i++;
} else {
prev = callBack(prev, this[i], i, this)
}
}
return prev
}
let r = [1, 2, 3].reduce((a, b, index, current) => a + b)
let r2 = [1, 2, 3].reduce((a, b, index, current) => a + b, 100)
console.log(r); // 6
console.log(r2); // 106

实现思路大体就是,利用将传入数组进行循环,执行函数并输出其结果。 假如有第二个参数,就对第二个参数进行处理。 若没有,则直接进行输出处理即可。

map

循环每一项,并对数组中的每一项进行处理,随后将处理后的结果以新数组的方式返回,不会改变原数组。

1
2
3
let arr = [1, 2, 3]
let newArr = arr.map(item => item * 2);
console.log(newArr, arr) // [ 2, 4, 6 ] [ 1, 2, 3 ]

filter

过滤数组,将结果为 false 的项过滤掉,并将结果返回。

1
2
3
let arr = [1, 2, 3]
let newArr = arr.filter(item => item != 2);
console.log(newArr, arr) // [ 1, 3 ] [ 1, 2, 3 ]

some

查看当前数组中是否存在与输出条件一致的结果,如果有则输出 true,反之为 false。 此方法与 every 方法相反

1
2
3
let arr = [1, 2, 3]
let newArr = arr.some(item => item == 2);
console.log(newArr) // true

every

查看当前数组中是否存在与输出条件不一致的结果,如果有则输出 true,反之为 false。 此方法与 some 方法相反

1
2
3
let arr = [1, 2, 3]
let newArr = arr.every(item => item == 2);
console.log(newArr) // false

find

查找数组中与函数条件一致的那一项结果,并将其返回。如果没找到,则返回 undefined

1
2
3
let arr = [1, 2, 3]
let newArr = arr.find(item => item == 2);
console.log(newArr) // 2

includes

查找数组中是否包含函数条件的那一项结果,有则输出 true,没有输出 false

1
2
let r = [1, 2, 3].includes(2)
console.log(r); // true

本篇文章由莫小尚创作,文章中如有任何问题和纰漏,欢迎您的指正与交流。
您也可以关注我的 个人站点博客园掘金,我会在文章产出后同步上传到这些平台上。
最后感谢您的支持!

请打赏并支持一下作者吧~

欢迎关注我的微信公众号