0%

在 JSON 物件陣列上增加一對鍵與唯一值

最近在學習的時候,常常遇到問題卻不知怎麼問人的窘狀,也發現自己常常把問題「複雜化」,而這個後果就是會讓自己如鬼打牆般轉不出來。程式設計最吸引我的一部份就是程式的結果或許一樣,但這中間的運作卻是多樣的,每次在看到其他人解出題來時,總會對於解題的方式感到讚嘆,自己不知要練多久才有那個程度。而也在透過「試著讀懂」其他人的程式碼的過程中又學習到許多。

在使用 Vue.js 的v-for時,需要使用v-bind:key='uniqueValue'去綁定一個唯一值,這樣可以讓 Vue 知道哪一個元素有變動而單一渲染,但是有時拿到的資料並沒有「唯一」值,如果使用陣列的索引值(index)當 key 的唯一值,會有因陣列的變動而索引值被改動的問題。如果後端給的資料沒有在每一筆資料裡給各唯一值,那麼只好自己生成,但是怎麼在 JSON 格式裡為每一個陣列裡的物間自動加上一對「鍵與唯一值」例如:

1
2
3
const amis = [{ name: 'Tracy', age: 42 }];
// 希望變成有 鍵與唯一值
const amis = [{ name: 'Tracy', age: 42, id: 唯一值 }];

想一想在程式中,有哪些東西會產生連續的數字?除了 索引值(index)之外,還有跑 for 回圈常用的計算陣列長度的arr.length與代表陣列每一個元素的變數i,利用迴圈和陣列長度就可以產生連續的唯一值。

1
2
3
4
const list = ['a', 'b', 'c', 'd', 'e'];
for (let i = 1; i < list.length + 1; i++) {
console.log(i);
} // 1 2 3 4 5

理解了上面的原理就可以思考,如果是 JSON 的資料型態如何利用 for 迴圈來增加一對鍵與唯一值?
自己把事情複雜化的把型別轉來轉去,使用了JSON.stringify()又使用了JSON.parse()都不行,因為自己連基本的「資料結構都還沒真的弄懂」,所以才會複雜化,來看了這篇JSON 格式與 JavaScript 解析教學範例,再一個個去試,才對這些方法比較瞭解也算是收穫。

後來又去 stackoverflow 繞了一圈,才看到可以這樣解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 原資料
const amis = [
{ name: 'tracy', age: 42 },
{ name: 'phi', age: 58 },
{ name: 'ayde', age: 38 },
];

for (let i = 0; i < amis.length; i++) {
console.log(amis[i]);
console.log(i + 1);
amis[i].uniqueId = i + 1;
}
console.log(amis);
// 結果
// amis = [
// { name: 'tracy', age: 42, uniqueId: 1 },
// { name: 'phi', age: 58, uniqueId: 2 },
// { name: 'ayde', age: 38, uniqueId: 3 },
// ];

試著寫成一支函式,以後就可以用了,但還是不夠完善,想試著把唯一 key 也提出來做參數,卻一直失敗。

1
2
3
4
5
6
function addUniKeyValue(arr) {
for (let i = 0; i < arr.length; i++) {
arr[i].uniqueId = i + 1;
}
return arr;
}

決定請教朋友給的提示,他沒幾分鐘就寫出來了。

1
2
3
4
5
6
7
8
9
function addUniKeyValue(arr, id) {
return arr.map((el, i) => {
el[id] = i + 1;
return el;
});
}

let amis3 = addUniKeyValue(amis, 'ok');
console.log(amis);

接著就是自己真的要好好理解這段碼了。

發現這樣得到的 陣列是淺拷貝,所以就來試了一下深拷貝,拿出去年學的,有點耗效能的 JSON.parse and JSON.stringify (Deep copy)深拷貝,也就是把陣列轉成字串,在字串轉成物件。
JSON.stringify:將物件轉字串。 / JSON.parse:將字串轉物件。
就可以利用這個函式將一份沒有鍵與唯一值的資料,轉成有鍵與唯一值的 JSON 資料,而且還可以指定鍵值名稱。

1
2
3
4
5
6
7
8
9
// 深拷貝
function addDeep(arr, id) {
arr.map((el, i) => {
el[id] = i + 1;
return el;
});
return JSON.parse(JSON.stringify(arr));
}
let amis3 = addDeep(amis, 'ok');

…待續…