一直以来都在函数式编程的大门之外徘徊,要入门的话首先得熟悉各种高阶函数,数组的reduce方法就是其中之一。
reduce方法将会对数组元素从左到右依次执行reducer函数,然后返回一个累计的值。举个形象的例子:你要组装一台电脑,买了主板、CPU、显卡、内存、硬盘、电源...这些零件是组装电脑的必要条件。
装的过程可以简单概括为拆掉每个零件的包装,再装到一起。类比一下reduce函数就可以明白了,那些零件就相当于要执行reduce方法的数组,对每个零件执行拆除包装的加工程序,就是对数组的每个元素执行reducer函数,把这些零件装到一起,就相当于reduce方法的任务,最终组装好的电脑相当于reduce方法的返回值。
reduce方法接收两个参数,第一个参数是回调函数reducer,第二个参数是初始值。reducer函数接收四个参数:
如果传入第二个参数,reduce方法会在这个参数的基础上开始累计执行。
概念讲了那么多,那reduce它的执行机制是怎样的呢?别着急,从用法入手一点一点分析。
来个最好理解的例子:数组求和
const arr = [1, 2, 3, 4]
const accumulator = (total, current, currentIndex, arr) => {
console.log(total, current, currentIndex, arr);
return total + current
}
console.log(arr.reduce(accumulator))
执行结果如下:
很明确,最终的结果就是把所有数组的元素都加起来。值得注意的是,它将数组的第一个元素作为累加的初始值,然后再依次对后边的元素执行reducer函数。
总共执行了三次,得出最终结果。那如果传入初始值,是怎样的执行顺序?
console.log(arr.reduce(accumulator, 3))
结果如下:
这次是以传入的初始值作为累加的起点,然后依次对数组的元素执行reducer。
假设对没有初始值的空数组调用reduce方法,则会报错:
Uncaught TypeError: Reduce of empty array with no initial value
讲了一些概念,但使用场景更重要,下面来看一下reduce方法都会有哪些用途。
compose是函数式编程的一种形式,用于将多个函数合并,上一个函数的返回值作为当前函数的入参,当前函数的返回值再作为下一个函数的入参,这样的效果有点类似于koa中间件的洋葱模型。
[a, b, c, d] => a(b(c(d())))
实际上和累加差不多,只不过把累加操作变成了入参执行,相加的结果变成了执行的返回值。redux的applyMiddleware内就使用了compose,目的是保证最终的dispatch是被所有中间件处理后的结果。
下面来以applyMiddleware中的compose为例,先看用法:
const result = compose(a, b, c)(params)
执行情况是这样:
(params) => a(b(c(params)))
返回的是一个函数,将params作为该函数的入参,被右侧第一个函数执行,执行顺序是从右到左执行,其余的函数的参数都是上一个函数的返回值。
看一下实现:
function compose(...funcs) {
// funcs是compose要组合的那些函数,arg是componse返回的函数的参数
if (funcs.length === 0) {
// 如果没有传入函数,那么直接返回一个函数,函数的返回值就是传进来的参数
return arg => arg
}
if (funcs.length === 1) {
// 如果只传入了一个函数,直接返回这个函数
return funcs[0]
}
return funcs.reduce((all, current) => {
return (...args) => {
return all(current(...args))
}
})
}
const array = [[0, 1], [2, 3], [4, 5]]
const flatten = arr => {
return arr.reduce((a, b) => {
return a.concat(b)
}, [])
}
console.log(flatten(array)); // [0, 1, 2, 3, 4, 5]
来看一下执行过程,
那么假设数组是这样呢?[[0, [111, 222], 1], [2, [333, [444, 555]], 3], [4, 5]],其实加个递归调用就可以
const array = [[0, [111, 222], 1], [2, [333, [444, 555]], 3], [4, 5]]
const flatten = arr => {
return arr.reduce((a, b) => {
if (b instanceof Array) {
return a.concat(flatten(b))
}
return a.concat(b)
}, [])
}
console.log(flatten(array)); // [0, 111, 222, 1, 2, 333, 444, 555, 3, 4, 5]
每次回调执行的时候,都会往对象中加一个key为字符串,value为出现次数的键值,若已经存储过字符串,那么它的value加1。
const str = 'adefrfdnnfhdueassjfkdiskcddfjds'
const arr = str.split('')
const strObj = arr.reduce((all, current) => {
if (current in all) {
all[current]++
} else {
all[current] = 1
}
return all
}, {})
console.log(strObj) // {"a":2,"d":7,"e":2,"f":5,"r":1,"n":2,"h":1,"u":1,"s":4,"j":2,"k":2,"i":1,"c":1}
const arr = ['1', 'a', 'c', 'd', 'a', 'c', '1']
const afterUnique = arr.reduce((all, current) => {
if (!all.includes(current)) {
all.push(current)
}
return all
}, [])
console.log(afterUnique); // ["1", "a", "c", "d"]
这种方式实际上处理的是promise的value,将上一个promise的value作为下一个promise的value进行处理。
const prom1 = a => {
return new Promise((resolve => {
resolve(a)
}))
}
const prom2 = a => {
return new Promise((resolve => {
resolve(a * 2)
}))
}
const prom3 = a => {
return new Promise((resolve => {
resolve(a * 3)
}))
}
const arr = [prom1, prom2, prom3]
const result = arr.reduce((all, current) => {
return all.then(current)
}, Promise.resolve(10))
result.then(res => {
console.log(res);
})
通过上面的用法,可以总结出来reduce的特点:
Array.prototype.myReduce = function(fn, base) {
if (this.length === 0 && !base) {
throw new Error('Reduce of empty array with no initial value')
}
for (let i = 0; i < this.length; i++) {
if (!base) {
base = fn(this[i], this[i + 1], i, this)
i++
} else {
base = fn(base, this[i], i, this)
}
}
return base
}
avaScript数组同后端语言一样,具有它自己的数据结构,归根结底,这种数据结构,本质就是一种集合。在后端语言中(如java,.net等),数组是这样定义的:数组是用来存储相同数据类型的集合
单个数字转汉字的解决方法:利用数组存储0-9的汉字、 ary.length和str.length不用多说,这是指ary数组和str字符串的长度。这里我们需要注意的是str.charAt(j)和ary[i],分别指在str这个字符串中索引为j的元素,在ary中索引为i的元素。
在 Javascript 循环中使用 async/ await 循环遍历数组似乎很简单,但是在将两者结合使用时需要注意一些非直观的行为。让我们看看三个不同的例子,看看你应该注意什么,以及哪个循环最适合特定用例。
今天说的数组和字符串去重呢,主要用到es6新的数据结构 Set,它类似于数组,但是成员的值都是唯一的,没有重复的值,所以活用Set来进行数组和字符串的去重。
数组方法:1、Array.join([param]) 方法:将数组中所有的元素都转换为字符串并连接起来,通过字符 param 连接,默认使用逗号,返回最后生成的字符串2、Array.reverse() 方法:将数组中的元素颠倒顺序(在原数组中重新排列它们),返回逆序数组
falsy(虚值)是在 Boolean 上下文中已认定可转换为‘假‘的值.JavaScript 在需要用到布尔类型值的上下文中使用强制类型转换(Type Conversion )将值转换为布尔值,比如:在条件语句或者循环语句中。
JavaScript中我们经常会遇到拷贝数组的场景,但是都有哪些方式能够来实现呢,我们不妨来梳理一下。扩展运算符(浅拷贝)自从ES6出现以来,这已经成为最流行的方法。
本文主要来讲数组api的一些操作,如简单实现扁平化n维数组、数组去重、求数组最大值、数组求和、排序、对象和数组的转化等。扁平化嵌套数组/展平和阵列孔——flat()
vue无法监听数组变化的情况,但是数组在下面两种情况下无法监听:利用索引直接设置数组项时,例如arr[indexofitem]=newValue;修改数组的长度时,例如arr.length=newLength
使用 ES5 语法来实现虽然会麻烦些,但兼容性最好,不用考虑浏览器 JavaScript 版本,使用 ES5 语法来实现虽然会麻烦些,但兼容性最好,不用考虑浏览器 JavaScript 版本。也不用引入其他第三方库。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!