JS數(shù)組Reduce的妙用,收藏等于學(xué)會(huì)!
本文轉(zhuǎn)載自微信公眾號(hào)「前端發(fā)現(xiàn)」,作者前端發(fā)現(xiàn)者。轉(zhuǎn)載本文請(qǐng)聯(lián)系前端發(fā)現(xiàn)公眾號(hào)。
說(shuō)到處理數(shù)組的方法,想必大家都不陌生了,今天我們一起來(lái)學(xué)習(xí)下理數(shù)組常見(jiàn)場(chǎng)景下的方法。
首先來(lái)看看 reduce 方法可以傳入哪些參數(shù)
- function(pre,cur,index,arr)
- pre:必需,初始值或計(jì)算結(jié)束后的返回值
- cur:非必需,當(dāng)前處理的元素
- index:非必需,當(dāng)前處理元素的索引
- arr:非必需,當(dāng)前元素所屬的數(shù)組對(duì)象
直接看看
- const list = [1,2,3,4,5]
- const result = list.reduce(function (pre, cur, index, arr) {
- console.log('pre:' + pre, 'cur:' + cur, 'index:' + index)
- return pre + cur
- })
- console.log(result)
- // => pre:1 cur:2 index:1
- // => pre:3 cur:3 index:2
- // => pre:6 cur:4 index:3
- // => pre:10 cur:5 index:4
- // => 15
可以看到,第一輪pre的值是數(shù)組的第一個(gè)值,然后當(dāng)前處理元素直接是元素的第二個(gè)數(shù)據(jù),索引是數(shù)組的1。第二輪的pre就是第一次邏輯處理 return pre + cur 返回的結(jié)果(即3)。以此類(lèi)推...共循環(huán)4輪。
再來(lái)看個(gè)相乘的處理邏輯的:
- const list = [1,2,3,4,5]
- const result = list.reduce(function (pre, cur, index, arr) {
- console.log('pre:' + pre, 'cur:' + cur, 'index:' + index)
- return pre * cur
- })
- console.log(result)
- // => pre:1 cur:2 index:1
- // => pre:2 cur:3 index:2
- // => pre:6 cur:4 index:3
- // => pre:24 cur:5 index:4
- // => 120
看著這么復(fù)雜,能舉個(gè)再簡(jiǎn)單的例子嗎?別問(wèn),問(wèn)就是有!
- const result = list.reduce((pre, cur) => pre + cur)
- console.log(result) // => 15
簡(jiǎn)單后再來(lái)個(gè)高級(jí)點(diǎn)的嘗鮮下。
數(shù)組去重
將數(shù)組傳輸之前,我們先來(lái)了解下 reduce 的另外一個(gè),即 initialValue。它是代表傳遞給函數(shù)的初始值,「可以理解為給pre設(shè)置了默認(rèn)的值」。
- const list = [1,1,3,5,5,7,9]
- let arr = list.reduce((pre,cur)=>{
- if(!pre.includes(cur)){
- return pre.concat(cur)
- }else{
- return pre
- }
- },[]) // => 給pre設(shè)置默認(rèn)的空數(shù)組[]
- console.log(arr) // => [1, 3, 5, 7, 9]
可以看到list數(shù)組的長(zhǎng)度為7,共循環(huán)7次(設(shè)置默認(rèn)的空數(shù)組,導(dǎo)致cur第一輪是數(shù)組的第一個(gè)數(shù)據(jù))。每循環(huán)一次就判斷pre數(shù)組里存不存在當(dāng)前循環(huán)的元素,若不存在則加入到pre數(shù)組去,否則就直接退出當(dāng)前循環(huán)。
數(shù)組二維轉(zhuǎn)一維
- let arr = [1,2,[4, 6], [1, 6], [2, 2]]
- let newArr = arr.reduce((pre,cur)=>{
- return pre.concat(cur)
- },[])
- console.log(newArr) // => [1, 2, 4, 6, 1, 6, 2, 2]
這里其實(shí)也就是利用了數(shù)組的 concat 方法,跟上面的使用也是大同小異,理順一下就可以理解的了。
數(shù)組多維轉(zhuǎn)一維
- let arr = [1, 2, [4, 6], [1, 6, [3, 6]], [1, [3, 4, [1, 2]], [2, 2]]]
- const newArr = (arr) => {
- return arr.reduce((pre, cur) => {
- return pre.concat(Array.isArray(cur) ? newArr(cur) : cur)
- }, [])
- }
- console.log(newArr(arr)) // => [1, 2, 4, 6, 1, 6, 3, 6, 1, 3, 4, 1, 2, 2, 2]
這里使用了 三目運(yùn)算 、 concat 數(shù)據(jù)拼接 、遞歸 的思路完成。先判斷當(dāng)前處理的元素(有可能是數(shù)組)是不是數(shù)組(Array.isArray(cur)),如果是再次執(zhí)行newArr,否則就直接處理當(dāng)前元素,即將cur拼接進(jìn)之前處理的數(shù)組中。
計(jì)算元素出現(xiàn)個(gè)數(shù)
講解這個(gè)之前我們先來(lái)回憶下for...in的用法:
for...in 聲明用于對(duì)數(shù)組或者對(duì)象的屬性進(jìn)行循環(huán)/迭代操作。
直接上
- var arr = ['張三','李四','王五']
- for (let x in arr)
- {
- console.log(x)
- // => 張三
- // => 李四
- // => 王五
- }
可以看到當(dāng)arr為數(shù)組時(shí) x 相當(dāng)于 for 循環(huán)的?? 標(biāo)
那當(dāng)arr為對(duì)象呢?
- const obj = {
- name: "張三",
- age: 18,
- height: "180"
- }
- for(let key in obj){
- console.log(key)
- // => name
- // => age
- // => height
- }
可以看到當(dāng)循環(huán)的“對(duì)象”是對(duì)象時(shí),循環(huán)的單項(xiàng)就是對(duì)象的屬性。
所以我們可以根據(jù)這個(gè)特性來(lái)判斷對(duì)象是否為數(shù)組/對(duì)象的元素/屬性。
- // 數(shù)組時(shí)判斷下標(biāo)
- let arr = ["a","b","2","3"]
- console.log("b" in arr) // => false
- console.log(2 in arr) // => true
- // 對(duì)象時(shí)判斷屬性
- let obj = {a:"a",b:"b",c:"2",d:"3"}
- console.log("b" in obj) // => true
- console.log(2 in obj) // => false
好的,回憶完這些知識(shí),我們來(lái)看看怎么完成這個(gè)需求
- let names = ['張三', '李四', '張三', '王五', '王五', '王五']
- let total = names.reduce((pre,cur)=>{
- if(cur in pre){
- pre[cur]++
- console.log("判斷為真:")
- console.log(pre)
- }else{
- pre[cur] = 1
- console.log("判斷為假:")
- console.log(pre)
- }
- return pre
- },{})
- console.log(total); // => {張三: 2, 李四: 1, 王五: 3}
首先先傳入一個(gè){}對(duì)象,說(shuō)明初始的pre為{}。那么第一輪判斷if的時(shí)候就變成 '張三' in {} 很明顯此時(shí)判斷條件是 false 。所以就執(zhí)行 else 里面的邏輯后變成:{'張三':1}。第二輪時(shí) 李四 也是如此。當(dāng)?shù)谌啎r(shí)再次遇到“張三”,此時(shí)對(duì)象是 {'張三':1,'李四':1} ,所以if判斷是 true ,所以張三直接+1。來(lái)看看打印情況:
- 判斷為假:
- // => {張三: 1}
- 判斷為假:
- // => {張三: 1, 李四: 1}
- 判斷為真:
- // => {張三: 2, 李四: 1}
- 判斷為假:
- // => {張三: 2, 李四: 1, 王五: 1}
- 判斷為真:
- // => {張三: 2, 李四: 1, 王五: 2}
- 判斷為真:
- // => {張三: 2, 李四: 1, 王五: 3}
屬性求和
- const list = [
- {
- name: '張三',
- age: 18
- },
- {
- name: '李四',
- age: 20
- },
- {
- name: '王五',
- age: 22
- }
- ]
- let total = list.reduce((pre, cur) => {
- console.log(cur)
- // => {name: '張三', age: 18}
- // => {name: '李四', age: 20}
- // => {name: '王五', age: 22}
- return cur.age + pre
- }, 0)
- console.log(total) // => 60
如此是不是省了使用 map 去求和呢?更簡(jiǎn)便可以這么寫(xiě):
- let total = list.reduce((pre, cur) => cur.age + pre, 0)
到此,今日的前端發(fā)現(xiàn)知識(shí)分享就到此結(jié)束了。