如何操作複雜的物件結構
Allen Shih 前端工程師

如何操作複雜的物件結構

在開發過程中,前端工程師們常常會遇到許多複雜的資料結構,結構與頁面的抽象及邏輯成正比,簡單來說,越複雜的結構就反應越複雜的頁面邏輯,當我們看到這些結構可以做哪些方法,去優化、簡化這些結構,來增加我們的開發效率並降低心智負擔呢?畢竟看到層層疊疊的物件及陣列,相信正常人的頭都會隱隱作痛XD
下面我們就來依序介紹:

1.處理方法(Api工具)
2.邏輯拆解(思考資料結構拆分)
3.組合及優化(解題)

處理方法

通常複雜的資料結構不免俗的就是物件及陣列的巢狀嵌套,要先來了解有哪些方法可以幫助我們處理,並用方法把目標解構出來吧!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
---條件篩選 
const ary = [1,2,3,4,5] ;
const aryMap=[{name:'allen'},{name:'joy'}]

1.filter 遍歷目標陣列篩選出符合條件的物件,並回傳陣列。

ary.filter((num)=>num>3) => [4,5]

2.find 遍歷目標陣列篩選出符合條件的物件,並回傳物件。

aryMap.find((d)=>d.name==='allen') => {name: 'allen'}

3.findIndex 遍歷目標陣列篩選出符合條件的物件,並回傳目標索引。

ary.findIndex((num)=>num>3) => 3 (找到目標後,就停止遍歷。)

4.includes 遍歷目標陣列篩選出符合條件的物件,並回傳布林值。

aryMap.includes((d)=> d.name === 'jack') => false

5.indexOf 回傳目標陣列中第一個被找到的索引值,若不存在則會回傳-1

ary.indexOf(3) => 2

---資料重組
1.map 遍歷陣列依照設定格式,回傳陣列。

ary.map((x)=>({num:x})) =>[{num:1},{num:2}...]

2.reduce 遍歷陣列依照閉包設定格式,回傳陣列、或物件。(非常重要,可以組出任意元素)
ary.reduce((acc,cur)=>{
acc[cur] = 'id'+cur+'!'
return acc
},{})

=>{1: 'id1!', 2: 'id2!', 3: 'id3!', 4: 'id4!', 5: 'id5!'}

以上的方法,有些是以閉包模式傳遞,並在內部遞迴後回傳出來,相當地有趣,筆者會在最後附上相關的實現內容,有興趣的話可以自己實做看看!會對這些方法的操作更加的熟悉!

不知道有沒有一個疑問,那就是上方都是陣列的方法,那物件呢?陣列的原型方法沒法使用阿!?
物件原型方法上的篩選methods的確很少XD,但我們可以把物件轉成陣列模式操作啊!

1
2
3
4
5
6
7
8
9
10
const obj = {a:'123',b:'234',c:'345'}

Object.keys 回傳物件key值陣列

Object.keys(obj) =>  ['a', 'b', 'c']

Object.values 回傳物件value值陣列

Object.values(obj) =>['123', '234', '345']

看到這個模式是否燃燒起你的小宇宙了呢!!我們來合體操作看看吧!

1
2
3
4
5

const obj2 = {1:{name:'allen'},2:{name:'joke'},3:{name:'mindy'}}

Object.values(obj2).filter((d)=>d.name==='mindy') => {name: 'mindy'}

邏輯拆解

找出我們所需的關鍵資料的一個想法或概念,我們可以透過畫出flow,去嘗試構思哪些資料是我們所需的,且在解題時為必要,
透過這些拆分,我們可以把複雜的資料給拆解出細小原子,在不斷的組合起來。

解題

在熟悉這些組合操作後,我們來挑戰一題較為困難的題目吧!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
const memberList = [
{
member: "Alex",
id: 1,
score: 85,
order: ["A", "C", "D", "B", "E"]
},
{
member: "jabo",
id: 2,
score: 83,
order: ["C", "A", "D", "E", "B"]
},
{
member: "allen",
id: 3,
score: 80,
order: ["A", "D", "E", "B", "C"]
},
{
member: "phobe",
id: 4,
score: 90,
order: ["D", "A", "C", "E", "B"]
},
{
member: "celia",
id: 5,
score: 60,
order: ["C", "A", "B", "D", "E"]
}
];

Q:按照分數高低,最後導出使用者的希望組別,組別不可以重複


memberList.sort((a,b)=>{a.score-b.score}) //先照高分順序排序


//按照 組別分組
let groupBox = memberList.reduce((acc, cur, i) => {
i === 0 && cur.order.forEach((d) => (acc[d] = [])); //先將組別放入物件中,並將值設為陣列
cur.order.forEach((d, x) => {
acc[d].push({ d, n: cur.member, s: cur.score, hopeIndex: x }); //依照順序送入陣列中
});
return acc;
}, {});

const map = [];
let pointer = 0;
//指針移動推入希望組別
while (pointer < memberList.length) {
for (key in groupBox) {
map.push(groupBox[key][pointer]); //此時的map陣列中就是按照分數高低及使用者意願的順序
pointer++;
}
}

但這解法有一個問題,就是for in 並保證key順序,若為重要資料陣列,建議還是另外保存索引值,較為理想喔!

若有更有趣的實現方式,歡迎在下方留言~

陣列實現
for in

 Comments