藍帶 · 系統全景
第 15 章

資料的形狀 —
清單、字典與 JSON

這章結束你會看懂清單、字典與 JSON,能追到資料藏在哪一層。

開場 · 一包有形狀的資料

你打開外送 App,畫面上看起來只是店名、餐點、地址、價格。可是對程式來說,這些不是一團文字,而是一包有形狀的資料。餐點通常是一排清單;收件人像一張名片;地址又藏在收件人裡面。AI 幫你寫 App 時,也是在搬動這些資料。你不用背很多語法,但你要看得出資料是「一排東西」、還是「一個東西的詳細資料」,以及它藏在哪一層。這章就是藍帶的入口:開始看懂系統真正流動的東西。

一、資料不是一坨,是有形狀的

前面幾章我們常把程式比喻成食譜:一步一步照做。到了藍帶,你要多看一層:食譜處理的食材,其實就是資料。所有 App 本質上都在做一件事:收進資料,整理資料,再吐出新的資料。記帳 App 收進一筆花費,吐出本月總額;外送 App 收進你的地址與餐點,吐出訂單狀態;天氣 App 收進城市名稱,吐出溫度與降雨機率。

問題是,資料如果全部散在桌上,程式會很難處理。你不會把通訊錄寫成「小安 0912 小美 0988 台北 高雄」這種一長串,因為人腦都會混亂,電腦更只會照字面做。你會自然地把它整理成一筆一筆:第一個人有姓名、電話、城市;第二個人也有姓名、電話、城市。這就是資料的形狀。

本章只抓兩個核心形狀。第一個是清單(array):一排同類型的東西,像排隊的人、購物車裡的商品、待辦事項。第二個是物件(object),也可以先想成字典:一個東西的詳細資料,像一張名片,上面有姓名、電話、城市。當清單裡每一格放的不是單純文字,而是一張名片,通訊錄就出現了。這句話很重要:很多真實 App 的資料,都是「清單裡裝物件」。

資料形狀決定了你怎麼問 AI、怎麼讀 AI 的 code、怎麼檢查錯誤。如果你能說出「這裡應該是一個訂單清單,每筆訂單都有收件人與商品清單」,AI 實習生就比較不會亂放資料。反過來,只說「幫我處理訂單資料」,它可能做出看似能跑、但很難擴充的形狀。

通訊錄最常見的形狀:清單裡裝物件。
const contacts = [
  { name: '小安', phone: '0912-000-111', city: '台北' },
  { name: '小美', phone: '0988-222-333', city: '高雄' }
];
console.log('通訊錄有 ' + contacts.length + ' 個人');
console.log('第一個人的城市:' + contacts[0].city);

二、清單 array:排隊的人與購物車

清單(array)最適合放「很多個同類東西」。你可以把它想成一排抽屜,每格有固定位置。排隊的人、點餐清單、每天的氣溫、測驗題目,都很適合用清單。清單的重點不是每個東西有多複雜,而是它們有順序,而且可以數第幾個。

程式裡取清單資料時,常會看到索引(index)。索引就是第幾格,但 JavaScript 的索引從 0 開始。第一格是 [0],第二格是 [1],第三格是 [2]。這一點剛開始很反直覺,卻非常實用:看到 items[1],你要立刻想到「第二個商品」,不是第一個。

清單也常跟 ch03 學過的迴圈一起出現。因為有一排東西,就會想要一個一個處理:把購物車每個商品加總、把每個學生分數檢查一遍、把每筆訂單畫到畫面上。你不用現在就寫很熟,但要看得懂 AI 產出的 code 為什麼會出現 forforEach:它正在沿著清單走。

判斷一個資料該不該用清單,可以問自己三件事:它是不是很多筆?每筆是不是同一類?順序或數量有沒有意義?如果答案大多是有,清單通常是好選擇。購物車不是一個商品,而是很多商品;搜尋結果不是一篇文章,而是一串結果;聊天紀錄不是一句話,而是一排訊息。這些都是清單的地盤。

清單有順序;程式的索引從 0 開始。
const cart = ['拿鐵', '貝果', '沙拉'];
console.log('第一項:' + cart[0]);
console.log('第二項:' + cart[1]);
console.log('總共有 ' + cart.length + ' 項');
cart.forEach(function(item, index) {
  console.log('第 ' + (index + 1) + ' 項是 ' + item);
});

三、物件 object:一張有欄位的名片

物件(object)適合描述「一個東西的詳細資料」。你可以把它想成一張名片、一本資料卡,或一個抽屜櫃。每個欄位都有名稱,欄位名稱叫鍵(key),欄位裡的內容叫值(value)。例如一個人有 namephonecity;一筆訂單有 idcustomeritemstotal

清單回答「有幾個、排第幾個」,物件回答「這個東西有哪些屬性」。如果清單像排隊的人,物件就像其中一個人拿出的名片。你不會用第 0 格、第 1 格去記名片,因為名片上最重要的是欄位名稱。person.nameperson[0] 清楚太多,連不會寫程式的人也能猜到它在拿姓名。

這也是你讀 AI code 的捷徑。看到點點語法,例如 order.totaluser.emailproduct.price,大多是在從物件裡拿某個欄位。變數名稱如果取好,code 就像半句人話。你不用把每個符號背成考試題,只要練習把它翻成白話:「從訂單裡拿總價」、「從使用者裡拿 email」、「從商品裡拿價格」。

設計物件時,欄位名稱要穩定、明確、同一套。不要一筆叫 phone,另一筆叫 tel,第三筆叫 mobile,這會讓程式和 AI 都困惑。好的資料形狀,會讓後面的畫面、計算、測試都變簡單。這就是藍帶開始要養成的直覺:先整理資料,再談功能。

物件用 key:value 描述一個東西的細節。
const person = {
  name: '小安',
  phone: '0912-000-111',
  city: '台北'
};
console.log(person.name + ' 住在 ' + person.city);
console.log('電話欄位是:' + person.phone);

四、巢狀 nested:資料一層包一層

真實世界很少只有一層。外送訂單不是只有總價,它有收件人;收件人裡有地址;訂單裡有很多餐點;每個餐點又有名稱、數量、單價。這種一層包一層的資料,叫巢狀(nested)。巢狀不是高深技巧,只是把清單和物件組合起來。

最常見的三種組合是:清單裡裝物件、物件裡裝清單、物件裡再裝物件。通訊錄是清單裡裝物件;一筆訂單裡的餐點是物件裡裝清單;收件人地址則常是物件裡再裝物件。當你看到很多大括號 {} 和中括號 [] 交錯,不要慌。先問:現在這一層是「一排東西」,還是「一張資料卡」?

讀巢狀資料的技巧,是像走路一樣一站一站走,不要跳。要找「第一筆訂單的收件人城市」,路徑可以翻成白話:訂單清單的第一筆 → 這筆訂單的收件人 → 收件人的地址 → 地址裡的城市。對應到 code 可能是 orders[0].customer.address.city。每一段都合理,整條路就不神秘。

AI 很常在巢狀資料上出錯,特別是拿錯層級。它可能以為城市在 order.city,但真正資料放在 order.customer.address.city。你如果會看形狀,就能指出:「城市不是訂單本身的欄位,它在 customer 的 address 裡。」這種回饋比「它壞了」有用太多。

巢狀資料要一層一層走路徑。
const order = {
  id: 'A1001',
  customer: {
    name: '小美',
    address: { city: '高雄', district: '左營區' }
  },
  items: [
    { name: '雞腿便當', price: 120, qty: 1 },
    { name: '紅茶', price: 30, qty: 2 }
  ]
};
console.log('城市:' + order.customer.address.city);
console.log('第二個商品:' + order.items[1].name);
console.log('第二個商品小計:' + order.items[1].price * order.items[1].qty);

五、JSON:全世界交換資料的通用語

JSON(JavaScript Object Notation)是程式交換資料時最常見的格式。名字看起來像工程師術語,但你已經會八成了:它就是清單與物件的寫法,拿來當資料包裹。App 跟伺服器說話、網站載入商品、AI 工具回傳設定,常常都是一包 JSON。

JSON 跟 JavaScript 物件很像,但規矩更嚴。欄位名稱要用雙引號,文字也要用雙引號,不能放註解,最後一個欄位後面通常不要多逗號。這些規矩不是為了刁難你,而是為了讓不同語言、不同系統都能讀同一包資料。就像表格欄位要對齊,大家才知道哪格是哪個意思。

你不需要手寫大型 JSON,但要會讀。讀 JSON 時先看最外層:是 [] 還是 {}?如果最外層是 [],代表整包資料是一個清單,裡面可能很多筆。若最外層是 {},代表整包資料是一個物件,先找它有哪些 key。接著再往裡面看:哪個 key 裡又藏清單?哪個 key 裡又藏物件?

JSON 是 ch16 API 的前置能力。下一章你會看到程式向服務窗口送出 request,拿回 response,而 response 裡最常見的內容就是 JSON。會讀 JSON,就像會看包裹上的標籤:你知道資料從哪來、裡面有什麼、要從哪一層拆出你要的東西。

JSON.parse 把文字資料包拆成可操作的物件。
const jsonText = '{"name":"拿鐵","price":80,"tags":["熱飲","咖啡"]}';
const drink = JSON.parse(jsonText);
console.log(drink.name + ' 售價 ' + drink.price + ' 元');
console.log('第一個標籤:' + drink.tags[0]);
const backToText = JSON.stringify(drink);
console.log(backToText);

六、實戰讀法:從外送訂單找總價

現在把觀念收成一個實戰讀法。假設你拿到一份外送訂單 JSON,先不要急著找總價。第一步看最外層形狀:如果是一個物件,代表這是一筆訂單;如果是清單,代表可能有很多筆訂單。第二步掃 key:有沒有 customeritemspaymenttotal 這種像名片欄位的字。第三步才沿路徑找目標。

找總價時,你會遇到兩種設計。有些資料直接有 total 欄位,代表系統已經算好;有些資料只有每項商品的 priceqty,需要自己加總。這兩種都合理,但不能混淆。若畫面顯示 180 元,JSON 裡的商品小計加起來卻是 160 元,你就抓到一個需要驗證的地方。這時候先不要改畫面,先確認資料源頭,再確認畫面拿的是同一條路徑。

這裡也接回 ch12 的驗證心態。資料看懂之後,測試才有方向。你可以列出預期:兩個 30 元紅茶應該是 60 元;120 元便當加 60 元紅茶應該是 180 元;付款欄位的總價也應該是 180 元。若其中一層對不上,bug 可能不是按鈕壞,而是資料形狀或計算路徑錯了。

真正的差距在這裡。純 vibe coder 看到一大包 JSON,只會貼給 AI 說「幫我修」。你會先指出資料形狀:「orders 是清單,第二筆的 customer.address.city 是城市;items 裡每個物件有 price 和 qty;total 應該等於小計加總。」這種描述會讓 AI 實習生更像有人管理,而不是自己亂猜。

讀懂資料形狀後,就能檢查總價是不是對得上。
const deliveryOrder = {
  id: 'D-2026-0715',
  items: [
    { name: '雞腿便當', price: 120, qty: 1 },
    { name: '紅茶', price: 30, qty: 2 }
  ],
  payment: { total: 180, method: 'creditCard' }
};
let subtotal = 0;
deliveryOrder.items.forEach(function(item) {
  subtotal = subtotal + item.price * item.qty;
});
console.log('商品加總:' + subtotal);
console.log('付款總價:' + deliveryOrder.payment.total);
console.log('兩邊一致嗎?' + (subtotal === deliveryOrder.payment.total));
招牌互動 · json-explorer

JSON 探險家

展開訂單樹,依題目點到正確節點;路徑追蹤器會顯示目前位置的取值寫法。

✓ JSON 探險完成 你已經能沿著 JSON 路徑找到資料,這就是 API 時代的識字能力。

會讀 JSON 之後,你跟 AI 對話不再只說「資料壞了」。你會指出「這裡是清單」、「這裡是物件」、「城市在 customer.address.city,不在 order.city」。當 AI 實習生拿錯層級時,你能用路徑糾正它。這會直接提升你串 API、修畫面資料、檢查總價錯誤的效率。

隨堂測驗 · 5 題

檢查一下這章

下一章預告

下一章我們把 JSON 接到世界:看懂 API 如何用 request 和 response 跟服務說話。