資料進出 API 時,其實都被「拷貝」了一份
前言
你有沒有想過:當前端把資料送給後端 API,或是 API 把資料回傳給你的時候,這些資料是「同一份」被搬來搬去,還是被「複製」了一份新的?
答案是:每一次資料進入或離開 API,都會產生一份新的拷貝(copy)。這篇文章會用淺白的方式,帶你理解這件事到底是怎麼發生的、為什麼會這樣,以及對我們寫程式有什麼影響。
用一個生活比喻來理解
想像你要寄一封信給朋友:
- 你先把想說的話寫在信紙上(把資料轉成可以傳送的格式)
- 郵差把信送到朋友家(透過網路傳輸)
- 朋友收到信後,讀懂內容並記在腦中(把資料還原成程式可以使用的形式)
注意喔!你腦中的想法並沒有「直接飛進」朋友的腦袋,而是經過「寫下來 → 傳送 → 讀進去」這三個步驟。每一步都是一次複製,你朋友腦中的版本,其實是一份全新的拷貝。
API 傳資料也是一模一樣的道理。
資料進出 API 的完整流程
步驟一:序列化(Serialization)— 資料「離開」你的程式
在 JavaScript 裡,你的資料通常是一個物件(object),它存在於記憶體中:
const user = {
name: "小明",
age: 25
};
但這個物件沒辦法直接在網路上跑,因為網路只能傳送文字或位元組(bytes)。所以我們要先把它「轉成文字」,這個動作叫做序列化:
const jsonString = JSON.stringify(user);
// 結果是一段純文字:'{"name":"小明","age":25}'
這時候,jsonString 已經是一份全新的拷貝了!它跟原本的 user 物件是兩個完全獨立的東西。
步驟二:網路傳輸 — 資料在路上又被複製好幾次
當你用 fetch 把資料送出去:
fetch("https://api.example.com/users", {
method: "POST",
body: jsonString
});
這段文字會被切成一個個小封包(packets),經過網卡、路由器、伺服器的網卡……每經過一個地方,資料都會被再複製一次。
步驟三:反序列化(Deserialization)— 資料「進入」API
後端伺服器收到的是一串文字,它必須把文字「還原」成程式看得懂的物件,這個動作叫做反序列化:
// 後端(以 Node.js 為例)
const userData = JSON.parse(receivedString);
這個 userData 又是一份新的拷貝,跟你前端那個 user 物件完全沒有關聯,只是內容長得一樣而已。
步驟四:回傳資料時,整個流程再走一遍
API 回傳資料給前端時,同樣的事情會反過來再發生一次:
後端物件 → 序列化成文字 → 網路傳輸 → 前端收到文字 → 反序列化成新物件
所以前端拿到的回應資料,也是一份全新的拷貝。
為什麼一定要拷貝?不能共用同一份嗎?
答案很簡單:因為前端和後端根本活在不同的世界。
- 前端的資料存在使用者電腦的記憶體裡
- 後端的資料存在伺服器的記憶體裡
這兩台機器可能相隔千里,記憶體是完全獨立的,物理上就不可能「共用」同一份資料。唯一的辦法就是把資料轉成文字、透過網路傳過去,再在對方那邊「重建」一份。
這件事對寫程式有什麼影響?
1. 改了前端的資料,後端不會知道
因為是兩份獨立的拷貝,你在前端修改物件,後端的資料完全不會變。想要更新後端資料,一定要再發一次 API 請求。
const user = await fetch("/api/user/1").then(res => res.json());
user.name = "小華"; // ❌ 只改到前端的拷貝,後端資料庫完全沒變!
// ✅ 必須明確地把修改送回去
await fetch("/api/user/1", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(user)
});
2. 有些東西「拷貝」不過去
序列化只能處理純資料,像是文字、數字、陣列、一般物件。以下這些東西會在傳輸過程中「消失」或「變形」:
const data = {
name: "小明",
sayHi: function () { console.log("嗨"); }, // ❌ 函式會直接消失
createdAt: new Date(), // ⚠️ Date 會變成文字
amount: undefined // ❌ undefined 會消失
};
JSON.stringify(data);
// 結果:'{"name":"小明","createdAt":"2026-07-15T08:00:00.000Z"}'
所以從 API 拿到的日期,記得要自己轉回 Date 物件:
const realDate = new Date(response.createdAt);
3. 大量資料的拷貝會影響效能
既然每次進出 API 都要序列化、傳輸、反序列化,資料越大,這些拷貝的成本就越高。這也是為什麼:
- API 通常會做分頁(一次只回傳 20 筆,而不是 10 萬筆)
- 回應資料常會只挑需要的欄位,不會整包資料庫原封不動丟出來
- 傳輸過程常會啟用 gzip 壓縮來減少體積
4. 拷貝其實也是一種保護
因為每一方拿到的都是自己的拷貝,所以不用擔心「別人改到我的資料」。前端怎麼玩弄自己那份資料,都不會直接弄壞後端的資料,這讓系統的邊界更清楚、更安全。
重點整理
| 觀念 | 說明 |
|---|---|
| 序列化 | 把記憶體中的物件轉成文字(如 JSON),產生第一份拷貝 |
| 網路傳輸 | 資料在傳送過程中會被複製多次 |
| 反序列化 | 收到的文字被還原成新物件,又是一份拷貝 |
| 兩邊獨立 | 前端和後端的資料互不相干,改 A 不會動到 B |
| 資料會失真 | 函式、undefined 等傳不過去,Date 會變文字 |
| 效能考量 | 資料越大拷貝成本越高,記得分頁與精簡欄位 |
結語
「資料進出 API 都會被拷貝」聽起來很技術,但本質上就像寄信一樣:內容被寫下、送出、再被對方讀進腦中,每一步都是複製,而不是搬移。理解這個觀念之後,你就會明白為什麼改了前端資料後端不會變、為什麼日期從 API 回來會變成字串,這些日常開發中常見的「奇怪現象」,其實都非常合理!