Vue 2 核心实现思路与 Vue 3 的主要区别
Vue 2 核心实现思路与 Vue 3 的主要区别
下面从响应式、实例与 API 形态、渲染与编译等角度,概括 Vue 2 的设计逻辑,以及 Vue 3 在架构上的演进(不涉及具体业务代码细节)。
Vue 2:围绕「选项式」与 Object.defineProperty
响应式
- 对 data 返回的对象做递归遍历,用
Object.defineProperty把每个属性变成 getter / setter。 - 依赖收集:渲染或计算属性读值时,把当前的 Watcher 记到该属性的 Dep 上;派发更新时在 setter 里通知 Dep 里的 Watcher。
- 局限:
- 无法检测对象新加 / 删除属性(需
Vue.set/Vue.delete或this.$set)。 - 数组通过改写原型上的变异方法(
push、splice等)触发更新,下标直接赋值、length 修改等场景需要额外处理或Vue.set。 - 递归遍历在深层大对象上有一次性成本。
- 无法检测对象新加 / 删除属性(需
组件与 API
- 选项式 API(Options API):
data、methods、computed、watch、生命周期钩子等写在同一对象上,按选项组织。 - 每个组件实例对应一个
Vue子类(继承合并选项后的构造器),实例上有$data、$props、$refs等运行时属性。
渲染
- 虚拟 DOM:
render生成 VNode,diff 后更新真实 DOM。 - 模板在构建时编译成
render(运行时 + 编译器配合)。
Vue 3:可组合的响应式系统与「代理」模型
响应式:Proxy + 惰性追踪
- 使用
Proxy代理对象,惰性:访问到哪一层才包装哪一层(Vue 2 则常在一开始递归整棵树)。 - 能拦截:新增/删除属性、数组下标与
length(在合法范围内)等,不再需要$set(对象仍建议用新对象替换以保持不可变风格清晰)。 - effect / track / trigger 模型与 Vue 2 的 Dep / Watcher 思想对应,但实现更模块化,便于 tree-shaking(未使用的功能可摇掉)。
组合式 API(Composition API)
- 用
setup(或<script setup>)把逻辑按功能组织:ref、reactive、computed、watch、生命周期等以函数形式组合,更适合大型组件与逻辑复用(对标 React Hooks 的思路,但语义不同)。 - 选项式 API 仍完全支持,便于渐进迁移。
实例与全局 API
- 无「单一全局 Vue 构造函数」:
createApp创建应用实例,插件、全局组件挂在 app 上,避免 Vue 2 中多应用共享同一全局配置的问题。 - 内部实现采用 Proxy + 普通对象,不再依赖
this._data那套实例形态(对使用者透明)。
渲染与特性
- 编译器优化:静态提升、补丁标记(patch flag) 等,减少运行时比较量。
- Fragment:组件可多根节点。
- Teleport / Suspense 等内置能力在框架层一等公民化。
对照小结
| 维度 | Vue 2 | Vue 3 |
|---|---|---|
| 响应式核心 | defineProperty + 递归 | Proxy + 惰性 |
| 新增/删除属性 | 需 $set / Vue.set | 原生可追踪(常规用法) |
| 数组部分场景 | 需注意下标等 | 模型更一致 |
| 逻辑组织 | 以选项为主 | 组合式为主,选项式保留 |
| 应用入口 | new Vue() | createApp() |
| 类型与 TS | 支持较弱 | 以 TS 友好为设计目标之一 |
| 体积 | 相对整块打包 | 模块化,易 tree-shaking |
迁移与选型提示
- 新项目:默认 Vue 3 + Vite 已是社区主流栈。
- 老项目:可按模块逐步迁移,或先用 @vue/compat 构建模式做兼容过渡(详见官方迁移指南)。
更细的源码级对比可参考 Vue 官方文档与演进说明:Vue 3 文档、从 Vue 2 迁移。
