本章為 JavaScript 核心重構的第六天,將帶領你破解陣列與物件的傳址詛咒。透過「爆破影印術」的比喻,解析如何運用展開運算子 (...) 瞬間斷開與原版資料的靈魂連結。本文除了介紹資料合併與覆蓋的實戰技巧,更進一步探討淺拷貝 (Shallow Copy) 與深拷貝 (Deep Copy) 的差異及陷阱,穩固高階開發中資料不可變性 (Immutability) 的實作基礎。
Day 06: 原理篇 —— 影印術!展開運算子 ...
本文同步分享於2026鐵人賽:JS 核心重構:勇者轉職傳說
孩子,在踏上今日的領地前,先坐下來喝杯酒吧。 修煉的路很長,別急著奔跑,先聽聽這份卷軸裡的古老叮嚀。
我在每一站的盡頭都為你鋪設了 「實戰演武場 CodePen」。那不只是程式碼的拼湊,而是你在這場暴風雨中,試圖用邏輯點燃的一顆星火。
成功突圍後,別忘了帶著你的戰利品回到 「QuestBoard 佈告欄」。在那裡,你會發現自己從不孤單,公會的夥伴們都正舉杯等待你的歸來。
記住...
「 導師看重的從來不是你的劍法有多華麗,而是當你被邏輯擊潰、滿身泥濘後,依然選擇握緊理性的劍柄,再次向真相發起衝鋒的勇氣。 」
💡 【導師講義:底層真相探究】
1. 打破容器的「爆破影印術」
展開運算子 ... 的動作極其簡單:它就是把裝在「陣列」或「物件」裡的舊物資全部「倒出來」,放在空中供你重新運用。
const oldScrolls = ["火球術", "治癒術"];
// ✅ 影印術:變出一個新木箱 [],再把舊捲軸 ... 倒進去
const newScrolls = [...oldScrolls, "傳送術"];
console.log(newScrolls); // ["火球術", "治癒術", "傳送術"]
console.log(oldScrolls); // ["火球術", "治癒術"] (原版毫髮無傷,連結已斷開!)
2. 資料重組的「合併與覆蓋」
影印術最強的地方在於,你可以在合併的瞬間,對資料進行「進化」。
const baseSkill = { category: "魔法", mp: 10 };
const fireball = { name: "火球術", mp: 50 };
// ✅ 兩組合併:後面的內容會蓋掉前面的内容 (Overwriting)
// 就像是在新箱子裡先放舊零件,再把改良零件丟進去,重複的會被替換。
const superFireball = {
...baseSkill,
...fireball,
level: "Max",
};
console.log(superFireball);
// { category: "魔法", name: "火球術", mp: 50, level: "Max" }
| 修煉招式 | 標籤賦值 (=) | 展開影印 (...) |
|---|---|---|
| 核心結果 | 共享同一把鑰匙 | 打造全新實體 |
| 修改副作用 | A 改,B 跟著變 | 各走各路,互不干擾 |
| 記憶體狀態 | 指向同一個地址 | 產生獨立新地址 |
3. 邏輯流向圖解
想像這是一個 「影印現場」。展開運算子就像是一台快速影印機,它把大箱子(物件)的殼印了一份,但裡面的貴重保險箱(嵌套物件)依然只有一張 「同樣的提貨單」。而深拷貝則是直接派人去另一個城市,重新打造了一個完全一模一樣、且內外都獨立的新保箱。

⚔️ 【戰術對抗:學長與學弟的代碼對決】
招式示範:小隊集結 (陣列合併)
❌ 冒險學弟:吃力的「手動接龍」
- 負能量評級:🔴 寫法生硬 / 🔴 難以閱讀
const teamA = ["戰士", "法師"];
const teamB = ["牧師", "弓箭手"];
// 雖然能用 concat,但在多組數據合併時會變得很混亂
const fullTeam = teamA.concat(teamB);
✅ 勇者學長:直覺的「空投合併」
- 利潤評級:🟢 極致優雅 / 🟢 一目瞭然
const teamA = ["戰士", "法師"];
const teamB = ["牧師", "弓箭手"];
// 像把兩個麻袋直接打開倒進大麻袋一樣簡單
const fullTeam = [...teamA, ...teamB];
學長的寫法就像是在戰場上同時召喚兩支軍隊,你一眼就能看出最終的「大名單」長什麼樣子。這就是程式碼的「描述力」。
🏰 【勇者精英課:邁向職人的進階架構】
1. 影印機的極限:淺拷貝 (Shallow Copy)
孩子,別以為 ... 是無敵的。它雖然會影印大箱子,但如果箱子裡還裝著 「另一個小箱子」,影印機印出來的依然是 同一把小箱子的鑰匙。
const hero = { name: "辛梅爾", bag: { coin: 10 } };
const clone = { ...hero };
clone.bag.coin = 999;
console.log(hero.bag.coin); // 999 (救命!裡層物件還是連著的!)
當你處理「多層嵌套」的物資時,請記得:展開運算子只管第一層。
2. 終極影印:深拷貝 (Deep Copy)
當你的寶箱裡疊了好幾層箱子(嵌套物件)時,我們需要施展更徹底的「次元斷開術」。
-
招式 A:次元切割術 (
JSON.parse/stringify) 這是公會裡最古老也最常用的招式。我們先將整個物件轉化為 「無靈魂的字串 (JSON)」,再將字串重新生成為一個 「全新的物件」。app.jsconst hero1 = { name: "勇者", bag: { coin: 10 } };const hero2 = JSON.parse(JSON.stringify(hero1)); // ✂️ 徹底斷開!hero2.bag.coin = 999;console.log(hero1.bag.coin); // 10 (成功守衛!第一、二層都不再連動)⚠️ 實戰雷區:避開那些致命陷阱此招雖然強大,但它會遺忘物件裡的「魔法招式 (Function)」與「特殊印記 (Symbol)」。
-
招式 B:高階影印機 (
structuredClone()) 這是近年來公會引進的最高階武器。它能無損複製循環引用與特殊數據類型,但它極度排斥 「魔法函式 (Function)」。⚠️ 實戰雷區:避開那些致命陷阱如果你的物件裡藏著咒語(函式),發動
structuredClone()會導致 「次元崩潰 (DataCloneError)」。這就是為什麼資深前輩會說:「深拷貝資料時,請確保裡面只裝著純粹的物資,不要裝著會動的靈魂。」
3. 其餘參數 (Rest Parameters):剩下的都進口袋!
除了「倒出來」,... 還能當作 「萬能麻袋」,把它放在函式的接收處,它能捕捉所有剩餘的資料。
function captureLoot(firstGold, ...others) {
console.log(`金幣:${firstGold}`);
console.log(`其餘雜物:`, others); // others 自動變成陣列
}
孩子,導師當年維護「世界地圖物件」時,因為不懂 ... 的重要性,直接
const newMap = currentMap;
就去修改地圖上的魔王城位置。
結果那一秒,全伺服器的冒險者看到的地圖都亂了套,原本的新手村旁邊突然出現了魔王。那天我收到了公會歷史上最多的投訴信。
記住:「如果你打算修改某份前人傳下來的物件,請先『影印一份新的』再動手。這是身為資深勇者最基本的溫柔。」
天色微亮,營火雖已燃盡,但你眼中卻閃爍著領悟的光芒。在前往演武場挑戰關卡前,我已經幫你把靈魂碎片精煉成了這份「戰術錦囊」。拿好它,今日的任務不再是負擔,而是你證明自我的舞台。去吧,公會的英雄榜在等著你的戰報。
📝 【夥伴筆記:今日修煉精華】
這份筆記是你的隨身護身符,卡關時看一眼,真相就在裡面。
- 語法特徵:三個點
...,用於拆開容器。 - 防止副作用:用
[...old]或{...old}產生新副本,斷開傳址連結。 - 後蓋前規則:合併多個物件時,後方的相同屬性會覆蓋前方(Update 的關鍵)。
- 萬能口袋:在參數處使用
...收集剩餘資料。
🎯 【實戰演武場】
⚔️ 任務鑑定條件:
- 完成 📜 本日實戰任務 (CodePen)。
- 將 CodePen 網址貼至 QuestBoard,並回填鑑定報告:
⚔️ 任務鑑定條件:
- 初心者:影印術掌握度 (成就感發掘):
- 今天成功使用
...斷開影子分身的那一刻,你有沒有感受到數據終於「受你控制」的自由感?
- 今天成功使用
- 冒險者:影印機的選擇 (理性挑戰):[⚡ 觀念辨析]
- 如果我的裝備物件
gear裡面裝著一個「自動修復函式 (Function)」,為什麼使用JSON.parse(JSON.stringify())影印後,這招魔法會消失不見?
- 如果我的裝備物件
任務完成後,你的名字將永遠標記在公會的英雄榜上!
📚 【圖書館卷軸與前後站連結】
- 前導冒險: Day 00: 轉職說明會 —— JavaScript 為什麼是前端必備武器?
- 上一站冒險: Day 05:原理篇 —— 變數宣告與實體記憶體
- 下一站冒險: Day 07: 原理篇 —— 記憶膠囊:閉包與守護結界
- MDN 官方手冊: