Vue 3 已經 5 年了,為什么還有公司死守 Vue 2?
Vue 3 從 2020 年發布,到現在已經正式發布 5 年了,為什么還有那么多公司依舊在死守 Vue 2?
咱們先來看一組數據,通過 @vue/compiler-sfc(代表 Vue3) vs vue-template-compiler(代表 Vue2) 來看下雙方的下載量(PS:因為 Vue3 合并到主包后,無法直接區分 Vue3 和 Vue2 的下載量)

通過數據我們可以看出 雖然 @vue/compiler-sfc(代表 Vue3) 的下載量已經已經遠遠超過了 vue-template-compiler(代表 Vue2)。但是 依然有大約 25% 左右的下載量屬于 vue-template-compiler(代表 Vue2)。
這就證明市面上在運行的 Vue 項目中,依然有 至少四分之一 使用的是 Vue2。
1. “技術債” 太多,項目老且龐大
很多的 政企項目 老項目通常規模都比較龐大,上千甚至數千個頁面。遷移意味著:
- 代碼要大改:Options API 寫法和 Composition API 寫法是有的,幾乎不能無縫遷移。
- 生態要替換:Element UI、vuex、一些定制化的第三方庫,全都得換成對應的 Vue 3 版本。
- 團隊要學習:很多老員工只熟悉 Vue 2,遷移要有培訓成本。
動靜太大。成功了 Leader 沒什么業績,一旦出了問題 Leader 還得背鍋。 你想想,誰會推動這個事情?
2. 公司盈利能力有限,新功能優先級高于技術升級
我們要知道技術公司,并不是只有大廠。中、小、微 公司的占比可以達到 98% 以上。
而這些公司的老板們最怕的一件事就是:“原來跑得好好的項目,升級后突然一堆 bug。”
Vue 3 確實更先進,但對于企業來說,穩定性 > 技術新潮。如果業務沒有強烈的驅動(比如:新業務 Vue2 做不了),一般不會貿然升級。
那么都聊到這里了,接下來咱們就來看下面試中常見的 Vue 問題
1. Vue 2 和 Vue 3 的響應式原理區別
這是屬于一個面試中的超常見問題,但是很多同學反而回答的并不好。大部分同學只會說:“Vue2 是 Object.defineProperty。Vue3 是 Proxy” ,然后就 沒有了....
在現在這么卷的面試場景中,這樣肯定是 不行的呀
Vue 2:defineProperty + 依賴收集
Vue 2 是“攔屬性”的做法(Object.defineProperty 給每個屬性掛 getter/setter)
- 初始化時把對象 逐個屬性 轉成 getter/setter。讀時“收集依賴”,寫時“觸發依賴”。
- 深度監聽要 遞歸遍歷,對象越大,初始化越慢。
- 新增/刪除屬性感知不到,要 Vue.set(obj, 'x', v) / Vue.delete(obj, 'x')。
- 數組是老大難:改長度、用下標改值這種改法,監聽不到;框架內部通過 包一層原型 去重寫會變更的數組方法(push/splice/sort……)來曲線救國。
// Vue 2 下的老坑
vm.arr[1] = 100 // 不觸發更新
vm.arr.length = 0 // 不觸發更新
vm.obj.newKey = 1 // 不觸發更新
// 需要:
this.$set(vm.arr, 1, 100)
this.$set(vm.obj, 'newKey', 1)Vue 3:Proxy + WeakMap(桶) + effect
Vue 3 是“攔對象”的做法(Proxy 一把梭,讀寫都能劫持,還能知道讀的是哪個鍵、做的是什么操作)。
- 用 Proxy 直接 劫持對象層級,不需要挨個屬性包 getter/setter。
- 依賴收集結構是一個“大倉庫”:WeakMap(target) -> Map(key) -> Set(effects);讀用 track,寫用 trigger。
- 新增/刪除屬性、數組下標、length 改動、Map/Set 等原生集合,統統能感知。
- 可以“按操作類型”觸發更精準(比如 add/delete/clear 對 Map/Set 的影響范圍不同)。
// Vue 3 下這些都能更新
state.arr[1] = 100
state.arr.length = 0
state.obj.newKey = 1
state.set.add(1)
state.map.set('a', 1)然后給大家一個 一句話面試背誦版
Vue 2 用 defineProperty 劫持“屬性”,需要深遞歸,新增/刪除屬性和數組下標/length 改動監聽不到,只能靠 set/delete 和重寫數組變更方法補救;
Vue 3 用 Proxy 劫持“對象”,依賴用 WeakMap -> key -> effects 精確追蹤,支持 Map/Set 等集合,reactive/ref/computed 基于 effect 與調度器實現,可精細觸發、可自定義調度,性能和心智負擔都更優。
要是面試官繼續追問 “為什么 Vue 3 還能知道我改的是 arr.length?”
你就補一句:因為 Proxy 的 set 能拿到 目標、鍵、值,key === 'length' 的時候做專門的觸發邏輯,這在 Vue 2 的 getter/setter 里拿不到這么完整的上下文。
2. Vue 2 和 Vue 3 的 Diff 算法的區別
這個也是常見問題,但是這里會涉及到 算法,很多同學可能對算法并不是很熟悉。
因此我先把結論給大家拋出來:
Vue 2 的子節點 diff 更像“四指針+搬磚”(雙端指針法,必要時建一張 key→index 表,按匹配到哪就把哪兒搬過去);
Vue 3 的子節點 diff 是“先粗篩再精算”(兩頭同步 + 中間一坨一次性掛載/卸載;真要挪位置時再用 LIS 最長遞增子序列 算出最少移動)。
Vue 2:雙端指針
- 針對 keyed children,用四個游標在老/新列表兩頭對沖:oldStart?newStart、oldEnd?newEnd,還會嘗試交叉匹配(oldStart ? newEnd、oldEnd ? newStart)。
- 都沒對上時,再用一張 key→index 的表在老列表里定位“同 key 的舊節點”,找到了就把這個舊 DOM 挪到合適位置。
- 沒 key 或沒找到,就當成新節點 創建 DOM。
- 這個策略的好處是實現簡單、無需昂貴的預處理;但在“局部打散重排”的場景里,移動次數不一定最少,有時會“邊比邊搬”,搬得有點多。
小例子(老:[A,B,C,D] → 新:[B,A,D,C]):Vue 2 會在指針對沖的過程中,分別把 A、B、C、D 對來對去,多次移動,但整體復雜度仍是 O(n)。
Vue 3:快速 Diff + LIS 的“先粗后細”
Vue 3 的 patchKeyedChildren 大致分四步,思路更克制:
- 前綴同步:從左向右比,直到第一對不等為止。
- 后綴同步:從右向左比,直到第一對不等為止。
這兩步很常見于實際變更(前后加條目),能“秒過”大段不變區域。
- 一坨新增/一坨刪除:
若老的先耗盡,剩下的新節點整段 一次性掛載;
若新的先耗盡,老列表剩余整段 一次性卸載。
- 中段重排(真正的“難點”):
對中間這段構建 新Key→新Index 映射,并用一個 source 數組記錄“老節點在新位置的索引”(找不到記 -1)。
先把 source 中為 -1 的老 DOM 全部 卸載(新里沒有了)。
再在 source 上跑 LIS(最長遞增子序列),LIS 表示“本就順序正確、可以不動的那些 DOM”;
不在 LIS 里的,按新順序 最少次數地插/移,把坑補齊。
同樣的例子(老:[A,B,C,D] → 新:[B,A,D,C]):Vue 3 會很快同步兩頭(其實同步不了很多),進入中段后通過 source+LIS 直接算出“最少需要動誰”,移動次數更少。































