Vue的响应式原理?Vue2和Vue3有什么区别?

一、什么是 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 使用 tracktrigger 来进行依赖收集和触发更新,并且性能更好。

此外 Vue3 还引入了 Composition API,使得逻辑复用更加灵活,对 TypeScript 支持更好。

相关推荐
孟祥_成都1 小时前
Cursor 要被淘汰了?开发者最应该关注的 10 个信号
前端·人工智能
cxxcode1 小时前
Sentry browserTracingIntegration 实现原理深度解析
前端
孟沐1 小时前
大白话理解 Java 序列化:对标前端 JSON.stringify/parse
前端
忘ci2 小时前
electron、edge.js调用C#动态链接库的一些问题
前端
yannick_liu2 小时前
推荐一个可以在vue2中格式化json数据的插件
前端
可视之道2 小时前
Canvas 渲染引擎性能优化实战:从 15 FPS 到 55 FPS
前端
小猪努力学前端2 小时前
基于PixiJS的试玩广告开发-续篇
前端·javascript·游戏
bluceli3 小时前
前端构建工具深度解析:从Webpack到Vite的演进之路
前端
wuhen_n3 小时前
v-model 的进阶用法:搞定复杂的父子组件数据通信
前端·javascript·vue.js