一、面試官為什麼愛考「框架底層原理」?

面試中詢問 Vue2/Vue3 響應式差異,通常是為了評估工程師在實戰中的四個核心能力:

  1. 除錯(Debug)與避坑能力: 遇到畫面沒更新時,能瞬間判斷是「框架限制(如 Vue 2 陣列索引)」還是「邏輯錯誤」。
  2. 效能優化敏感度: 理解底層運作機制(遞迴遍歷 vs 懶加載),以避開大型數據的效能地雷。
  3. 技術遷移能力: 區分只會背語法的「API使用者」與懂底層架構的「工程師」。
  4. 技術驅動力: 展現主動探究「為什麼」的習慣,而不僅滿足於「能動就好」。

二、響應式底層核心差異: Object.defineProperty vs Proxy

比較維度 Vue 2 (Object.defineProperty) Vue 3 (Proxy)
攔截目標 針對「單一屬性(Property)」 針對「整個物件(Object)」
新增/刪除屬性 無法攔截 (需依賴 this.$set / $delete) 原生支援
陣列操作 不支援索引修改 (需 hack push 等原型方法) 原生支援 (包含修改長度、索引)
Map / Set 支援 完全不支援 原生支援
初始化效能 貪婪式 (Eager):需一次性遞迴遍歷整棵物件樹,大物件易卡頓。 懶加載 (Lazy):讀取深層屬性時才臨時代理,初始化極快。
原始物件引用 obj === observed (直接修改原物件) obj !== observed (產生全新代理包裹器)
IE 支援度 支援 IE9+ 不支援 IE (Proxy 無法被 Polyfill)

三、資料流異常與狀態管理陷阱

實戰中,若直接操作大型巢狀物件,極易引發「參照污染」或「UI狀態被洗掉」的嚴重 Bug。解決這些問題的核心原則是:保持單向資料流,並嚴格區分「業務資料」與「展示狀態」。

情境1: 表單編輯造成的「參照污染」

當從 Store 取出資料放入表單綁定 v-model 時,若使用淺拷貝,會導致深層屬性依然共用記憶體,使用者的輸入會直接竄改全域狀態。

❌ 異常寫法(淺拷貝陷阱):

// ❌ 這樣寫,當使用者在 input 輸入時,Store 裡面的 profile.name 會同步被改掉!
// 甚至還沒點擊「儲存」,全域狀態就已經被污染了。
const formData = ref({ ...store.user });

✅ 正確解法: 使用深拷貝(structuredClone)徹底切斷關聯

<template>
  <input v-model="formData.profile.name" />
  <button @click="save">儲存</button>
  <button @click="cancel">復原</button>
</template>

<script setup>
import { ref } from 'vue';
import { useUserStore } from '@/stores/user';
const store = useUserStore();

// ✅ 使用原生 API 進行深拷貝,產生毫無關聯的新物件
const formData = ref(structuredClone(store.user));

const save = () => { store.updateUser(formData.value); };
const cancel = () => { formData.value = structuredClone(store.user); };
</script>

情境2: API覆蓋導致「前端格式化/UI狀態」遺失

後端回傳原始資料(如 1500.5),前端需要格式化(如 $1,500.50)。若拿 API 資料直接暴力覆蓋 State,辛苦算出的格式化欄位會瞬間蒸發。

❌ 異常寫法(將 UI 狀態與業務資料混在一起):

// ❌ API 回來直接覆蓋,原本自己加的 formattedAmount 欄位就不見了
async refreshBalance() {
  const response = await api.getBalance();
  // response.data 只有 { asset: 'USDC', rawAmount: 1500.5 }
  this.wallet = response.data; 
}