一、什么是 Vue 的响应式
Vue 的核心能力就是 数据变化 → 自动更新视图。
例如:
javascript
data() {
return {
count: 1
}
}
css
<div>{{ count }}</div>
当执行:
ini
this.count = 2
页面会自动更新。
这个过程就是 响应式系统。
核心流程:
数据变化
↓
监听数据变化
↓
通知依赖更新
↓
重新渲染视图
Vue 内部有三个关键角色:
| 角色 | 作用 |
|---|---|
| Observer | 监听数据 |
| Dep | 依赖收集 |
| Watcher | 触发更新 |
二、Vue2 响应式原理(Object.defineProperty)
Vue2 使用:
css
Object.defineProperty
劫持对象属性。
示例
javascript
let obj = {}
Object.defineProperty(obj, "name", {
get() {
console.log("读取")
return value
},
set(newVal) {
console.log("修改")
value = newVal
}
})
当访问:
obj.name
会触发
scss
get()
当修改:
ini
obj.name = "Vue"
会触发
scss
set()
Vue 就利用这个机制实现响应式。
Vue2 内部流程
1 数据劫持
Vue 在初始化 data 时:
遍历所有属性
给每个属性添加 getter / setter。
伪代码:
javascript
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
// 收集依赖
dep.depend()
return val
},
set(newVal) {
val = newVal
// 通知更新
dep.notify()
}
})
}
2 依赖收集
当模板渲染:
{{ count }}
会生成一个 Watcher
Watcher 会读取数据:
count
触发
objectivec
getter
然后:
Dep 收集 Watcher
结构:
count
↓
Dep
↓
Watcher
3 数据变化
当执行:
kotlin
this.count++
触发:
objectivec
setter
然后:
scss
Dep.notify()
通知所有 Watcher 更新。
Watcher → 重新渲染
三、Vue2 的缺点
Vue2 的响应式有几个问题:
1 不能监听对象新增属性
ini
this.obj.age = 18
不会更新。
必须:
kotlin
Vue.set(this.obj, "age", 18)
2 不能监听数组下标
kotlin
this.arr[1] = 10
不会更新。
必须:
perl
splice
push
pop
shift
Vue 重写了数组方法。
3 初始化性能差
Vue2 会:
kotlin
递归遍历整个 data
如果数据非常大:
初始化慢
四、Vue3 响应式原理(Proxy)
Vue3 使用:
javascript
Proxy
代替
css
Object.defineProperty
示例:
javascript
let obj = { name: "vue" }
let proxy = new Proxy(obj, {
get(target, key) {
console.log("读取")
return target[key]
},
set(target, key, value) {
console.log("修改")
target[key] = value
return true
}
})
Proxy 优势
Proxy 可以拦截:
13 种操作
比如:
arduino
get
set
deleteProperty
has
ownKeys
所以:
新增属性
删除属性
数组下标
都能监听。
Vue3 响应式核心
Vue3 内部有两个核心方法:
track(收集依赖)
scss
track(target, key)
当读取数据:
arduino
get
收集依赖。
trigger(触发更新)
scss
trigger(target, key)
当数据变化:
arduino
set
通知更新。
核心结构:
javascript
targetMap
↓
WeakMap
↓
Map
↓
Set
结构图:
javascript
WeakMap
target -> Map
key -> Set(effect)
意思是:
对象
↓
属性
↓
依赖函数
五、Vue2 vs Vue3 区别
| 对比 | Vue2 | Vue3 |
|---|---|---|
| 响应式实现 | Object.defineProperty | Proxy |
| 监听新增属性 | 不支持 | 支持 |
| 数组下标 | 不支持 | 支持 |
| 初始化性能 | 需要递归遍历 | 按需代理 |
| API | Options API | Composition API |
| 代码体积 | 较大 | 更小 |
| TS支持 | 一般 | 非常好 |
六、Vue3 Composition API(核心变化)
Vue3 新增:
scss
setup()
例如:
javascript
import { ref } from "vue"
export default {
setup() {
const count = ref(0)
const add = () => {
count.value++
}
return { count, add }
}
}
优势:
逻辑复用更好
代码组织更清晰
TS友好
七、面试最佳回答(推荐说法)
面试时可以这样回答:
Vue 的响应式原理是通过数据劫持和依赖收集实现的。
在 Vue2 中,主要通过
Object.defineProperty对 data 的属性进行 getter 和 setter 劫持,当数据被读取时进行依赖收集,当数据被修改时通知依赖更新,从而触发视图重新渲染。Vue2 的缺点是无法监听对象新增属性和数组下标变化,因此需要使用
Vue.set或重写数组方法。在 Vue3 中,响应式系统改为使用
Proxy实现。Proxy 可以拦截更多操作,例如属性新增、删除、数组索引等,因此解决了 Vue2 的很多限制。同时 Vue3 使用track和trigger来进行依赖收集和触发更新,并且性能更好。此外 Vue3 还引入了 Composition API,使得逻辑复用更加灵活,对 TypeScript 支持更好。