讓json寫入/讀取順序一致的

 


你提出了一個非常核心且常見的問題!這幾乎是所有 JavaScript 開發者都會遇到的情況。

直接的答案是:你不能、也不應該依賴標準 JavaScript 物件 ({}) 的屬性順序。

影片中發生的情況(新增順序 1,2,3,4,讀取變 4,1,3,2)完美地印證了這個原則。

為什麼順序會亂掉?

  1. 物件的本質是「字典」,不是「列表」

    • JavaScript 的物件 (Object),在設計上是一個鍵-值對 (key-value) 的集合,就像一本字典。它的主要目的是讓你能夠透過一個「鍵」(例如 'timer1')快速找到對應的「值」(計時器的詳細資料)。

    • 它的設計沒有保證你放入的順序就是它儲存或讀取的順序。

  2. for...in 迴圈的不可靠性

    • 你提到的 for() 迴圈,很可能指的是 for...in 迴圈 (for (const key in myObject))。這個迴圈在規範中是不保證遍歷順序的。瀏覽器可以根據自己的內部優化(例如,它可能會先把數字鍵名的屬性排在前面)來決定遍歷的順序。

  3. JSON 的規範

    • JSON (JavaScript Object Notation) 格式本身也定義物件為「一個無序的鍵/值對集合」。所以當你將一個物件 JSON.stringify() 儲存,再 JSON.parse() 讀取回來時,順序同樣沒有任何保證。


正確的解決方案:使用陣列 (Array)

黃金法則:只要順序很重要,就一定要使用陣列 ([])。

陣列是專門為處理有序集合而設計的。你應該把你的資料結構從「物件」改成「物件的陣列」。

修改前的資料結構 (你的現狀,有問題的)

// 問題:無法保證順序
let timers = {
    'timer1': { time: '01:00', desc: '計時器1', status: 'stopped' },
    'timer3': { time: '00:00', desc: '計時器3', status: 'stopped' },
    'timer2': { time: '00:00', desc: '計時器2', status: 'stopped' }
};
  

// 解決方案:使用陣列來儲存物件,順序將被完美保留

let timers = [
    { id: 'timer1', time: '01:00', desc: '計時器1', status: 'stopped' },
    { id: 'timer3', time: '00:00', desc: '計時器3', status: 'stopped' },
    { id: 'timer2', time: '00:00', desc: '計時器2', status: 'stopped' }
];
  

關鍵改變

  • 最外層從 {} (物件) 變成了 [] (陣列)。

  • 每個計時器都是陣列中的一個獨立物件。

  • 我們為每個物件增加了一個 id 屬性,這樣你仍然可以唯一地識別和操作每一個計時器。


如何操作新的資料結構

1. 新增計時器

使用 array.push(),新的項目會被加到陣列的最後面,完美符合你的需求。

timers.push(newTimer);

// 現在 timers 陣列的順序就是 [timer1, timer3, timer2, timer4]
  

2. 讀取並渲染計時器 (保證順序)

使用 for...of 迴圈或 forEach 方法來遍歷陣列。它們保證會按照陣列的索引順序 (0, 1, 2, ...) 進行。

function renderTimers() {
    // 清空現有的顯示
    container.innerHTML = ''; 
    
    // 按照陣列順序遍歷
    for (const timerInfo of timers) {
        // 根據 timerInfo 創建 HTML 元素並添加到頁面上
        // 這裡的順序將與 timers 陣列的順序完全一致
        createTimerElement(timerInfo); 
    }
}
  

3. 刪除或修改某個計時器

你需要先根據 id 找到那個計時器。

const idToDelete = 'timer3';
timers = timers.filter(timer => timer.id !== idToDelete);

// 修改 id 為 'timer1' 的計時器的描述
const idToUpdate = 'timer1';
const timerToUpdate = timers.find(timer => timer.id === idToUpdate);
if (timerToUpdate) {
    timerToUpdate.desc = "新的描述";
}
  

總結

物件 {}陣列 []
用途快速查找 (key-value)有序列表
順序不保證保證 (按索引 0, 1, 2...)
新增obj[key] = valuearr.push(value) (加到結尾)
遍歷for...in (順序不保證)for...offorEach (順序保證)

為了修復你的問題,你需要:

  1. 將儲存計時器資料的結構從 {} 物件改為 [] 陣列。

  2. 在儲存到 chrome.storage 之前,確保它是陣列。

  3. chrome.storage 讀取後,使用 for...offorEach 來渲染,這樣順序就永遠不會錯了。

留言

這個網誌中的熱門文章

Offscreen Canvas

外部網頁新增 Google 日曆行程(URL模板)

計算 Canvas 文字最大字體