Vue2 和 Vue3 最大的区别,不只是 API 写法变了,而是:
响应式底层、组件组织方式、性能优化能力都发生了升级。
面试里最常问的就是:
-
Object.defineProperty和Proxy有什么区别 -
setup/ Composition API 为什么更好 -
Vue3 为什么性能更高
-
Tree-shaking 是怎么减少体积的
一、Vue2 和 Vue3 整体区别
| 维度 | Vue2 | Vue3 |
|---|---|---|
| 响应式实现 | Object.defineProperty |
Proxy |
| API 风格 | Options API | Composition API + Options API |
| 组件逻辑组织 | 按 data、methods、computed 分散 | 可以按功能集中组织 |
| 性能 | 相对较弱 | 编译和运行时都有优化 |
| Tree-shaking | 支持有限 | 更适合按需打包 |
| Fragment | 不支持多根节点 | 支持 |
| Teleport | 无 | 支持 |
| Suspense | 无 | 支持 |
| TypeScript | 支持一般 | 支持更好 |
二、响应式原理:defineProperty vs Proxy
Vue2:Object.defineProperty
Vue2 主要通过:
Object.defineProperty()
劫持对象已有属性。
例如:
javascript
const obj = {}
Object.defineProperty(obj, "name", {
get() {
return "Tom"
},
set(value) {
console.log("name 被修改了", value)
}
})
这样就可以监听:
obj.name = "Jack"
Vue2 的问题
1. 只能监听已有属性
例如:
javascript
data() {
return {
user: {
name: "Tom"
}
}
}
如果后来直接新增:
this.user.age = 18
Vue2 默认无法正常监听这个新增属性。
通常需要:
this.$set(this.user, "age", 18)
2. 删除属性也不能直接监听
例如:
delete this.user.name
Vue2 也不能直接感知。
一般需要:
this.$delete(this.user, "name")
3. 数组监听也需要特殊处理
Vue2 不能直接劫持数组索引变化,因此对:
push
pop
shift
unshift
splice
sort
reverse
这些方法做了额外封装。
三、Vue3:Proxy
Vue3 改成了:
Proxy
例如:
javascript
const user = {
name: "Tom"
}
const proxy = new Proxy(user, {
get(target, key) {
return target[key]
},
set(target, key, value) {
target[key] = value
return true
}
})
Proxy 监听的是:
整个对象,而不是某一个属性。
所以:
proxy.age = 18
新增属性可以监听。
delete proxy.name
删除属性也可以监听。
四、Proxy 为什么比 defineProperty 更适合 Vue3?
最核心区别:
defineProperty
→ 劫持对象已有属性
Proxy
→ 代理整个对象
因此 Proxy 可以更自然地处理:
新增属性
删除属性
数组变化
属性访问
属性修改
所以 Vue3 不再需要:
this.$set()
this.$delete()
这种额外 API。
五、Options API 和 Composition API
Vue2 常见写法:
javascript
export default {
data() {
return {
count: 0
}
},
computed: {
double() {
return this.count * 2
}
},
methods: {
add() {
this.count++
}
}
}
这种写法叫:
Options API
代码按照:
data
methods
computed
watch
进行分类。
六、Options API 的问题
小组件里非常清晰。
但是组件越来越复杂之后,一个功能的代码可能被拆散在很多地方。
例如"搜索功能"可能分布在:
data
computed
methods
watch
mounted
另外一个"分页功能"又分散在:
data
methods
watch
最后代码就会变成:
搜索逻辑
分页逻辑
用户逻辑
请求逻辑
互相穿插。
维护起来比较麻烦。
七、Vue3 的 Composition API
Vue3 引入 Composition API。
例如:
javascript
import { ref, computed } from "vue"
export default {
setup() {
const count = ref(0)
const double = computed(() => {
return count.value * 2
})
const add = () => {
count.value++
}
return {
count,
double,
add
}
}
}
这里:
setup()
就是 Composition API 的入口之一。
八、setup 是干什么的?
setup 的核心作用:
在组件创建时组织响应式数据、方法、计算属性和副作用逻辑。
可以在里面使用:
ref()
reactive()
computed()
watch()
watchEffect()
例如:
setup() {
const count = ref(0)
const add = () => {
count.value++
}
return {
count,
add
}
}
模板就可以直接使用:
<button @click="add">
{{ count }}
</button>
九、Composition API 最大优势
不是单纯"写法更新",而是:
可以按照功能组织代码。
例如:
用户功能
├─ 用户数据
├─ 用户请求
├─ 用户方法
└─ 用户监听
搜索功能
├─ 搜索关键字
├─ 搜索方法
└─ 搜索监听
而不是全部拆成:
data
methods
computed
watch
对于大型组件更容易维护。
十、Vue3 一定要用 Composition API 吗?
不是。
Vue3 同样支持:
Options API
所以你仍然可以:
export default {
data() {},
methods: {},
computed: {}
}
Vue3 只是新增了 Composition API。
所以更准确地说:
Vue2
→ 主要使用 Options API
Vue3
→ Options API + Composition API
十一、Vue3 为什么性能更好?
Vue3 在多个方面做了优化。
比较重要的有:
响应式系统优化
编译优化
虚拟 DOM 优化
Tree-shaking
Fragment
静态提升
Patch Flag
其中面试比较常见的是:
Tree-shaking
和虚拟 DOM 编译优化。
十二、什么是 Tree-shaking?
Tree-shaking 可以简单理解成:
打包时把没有使用到的代码删除。
例如:
import {
ref,
reactive,
computed
} from "vue"
如果实际只使用:
ref
现代打包工具会尽可能把没有使用到的部分移除。
最后打包:
只保留真正需要的代码
从而减少:
bundle 体积
十三、为什么 Vue3 更适合 Tree-shaking?
因为 Vue3 很多 API 都改成了独立导出形式。
例如:
import { ref } from "vue"
import { computed } from "vue"
import { watch } from "vue"
用什么就导入什么。
这样构建工具就更容易分析:
哪些代码使用了
哪些代码没使用
然后把没用的代码去掉。
十四、Fragment 是什么?
Vue2 一个组件模板通常需要一个根节点:
<div>
<h1>标题</h1>
<p>内容</p>
</div>
Vue3 支持 Fragment:
<h1>标题</h1>
<p>内容</p>
不再强制额外包一层 div。
这样:
DOM 结构更干净
无意义节点更少
十五、Teleport 是什么?
Vue3 新增:
<Teleport>
可以把组件内容渲染到 DOM 的其他位置。
例如弹窗:
<Teleport to="body">
<div class="modal">
弹窗
</div>
</Teleport>
虽然代码写在当前组件里,但最终 DOM 可以直接挂到:
<body>
下面。
很适合:
Modal
Dialog
Popover
十六、Suspense 是什么?
Suspense 主要用于处理异步组件加载状态。
可以理解为:
异步内容还没加载好
→ 显示 loading
加载完成
→ 显示真正内容
这也是 Vue3 增强异步组件体验的一部分。
十七、Vue2 和 Vue3 响应式核心区别
面试时可以直接这样回答:
Vue2 使用
Object.defineProperty劫持对象已有属性,新增和删除属性不能直接监听,数组也需要额外处理。
而 Vue3 使用:
Proxy
代理整个对象,因此可以更完整地监听:
属性读取
属性修改
属性新增
属性删除
数组变化
响应式实现更加统一。
十八、setup 的核心优势怎么回答?
可以这样答:
setup是 Composition API 的入口,可以把同一个功能相关的数据、方法、computed、watch 集中组织在一起。
相比 Vue2:
data
methods
computed
watch
按类型拆分代码,
Composition API 更适合:
复杂组件
逻辑复用
大型项目
TypeScript
十九、Tree-shaking 面试怎么回答?
可以直接说:
Tree-shaking 是构建工具在打包时分析 ES Module 的导入导出,把没有被使用的代码移除,从而减小最终 bundle 体积。
Vue3 API 更加模块化:
import { ref, computed } from "vue"
所以更容易进行 Tree-shaking。
总结
Vue2 和 Vue3 最核心的区别可以压缩成三点:
1. 响应式升级
Vue2
Object.defineProperty
↓
监听已有属性
Vue3
Proxy
↓
代理整个对象
2. 逻辑组织升级
Vue2
Options API
↓
data / methods / computed / watch
Vue3
Composition API
↓
setup / ref / reactive / computed / watch
Composition API 更适合按业务功能组织代码。
3. 性能与构建升级
Vue3 增加和强化:
Tree-shaking
Fragment
Teleport
Suspense
编译优化
虚拟 DOM 优化
所以 Vue3 在:
性能
体积
代码组织
TypeScript
大型项目维护
方面整体更优秀。
总结:
Vue3 不只是 Vue2 的语法升级,而是从响应式底层、组件逻辑组织到编译和性能体系的一次整体升级。