当前位置:首页 > VUE

vue依赖收集实现

2026-03-10 04:13:30VUE

Vue 依赖收集实现原理

Vue 的依赖收集是通过响应式系统实现的,核心是 ObserverDepWatcher 三个类的协作。

核心类与流程

Observer
负责将数据对象转换为响应式对象,通过 Object.definePropertyProxy 拦截属性的读取和修改操作。在属性被访问时触发依赖收集,修改时触发更新通知。

class Observer {
  constructor(value) {
    this.value = value
    this.walk(value)
  }
  walk(obj) {
    Object.keys(obj).forEach(key => {
      defineReactive(obj, key, obj[key])
    })
  }
}

Dep(依赖管理器)
每个响应式属性都有一个对应的 Dep 实例,用于存储所有依赖该属性的 Watcher。提供 depend 方法收集依赖,notify 方法通知更新。

class Dep {
  constructor() {
    this.subs = new Set()
  }
  depend() {
    if (Dep.target) {
      this.subs.add(Dep.target)
    }
  }
  notify() {
    this.subs.forEach(watcher => watcher.update())
  }
}
Dep.target = null // 全局唯一的当前 Watcher

Watcher(观察者)
代表一个依赖关系,在计算属性、模板渲染等场景中创建。初始化时会触发属性的 getter,从而将自身添加到 Dep 中。

class Watcher {
  constructor(getter) {
    this.getter = getter
    this.get()
  }
  get() {
    Dep.target = this
    this.value = this.getter() // 触发依赖收集
    Dep.target = null
    return this.value
  }
  update() {
    this.get()
  }
}

依赖收集流程

  1. 数据劫持
    defineReactive 为每个属性创建闭包的 Dep 实例,并在 getter 中调用 dep.depend()
function defineReactive(obj, key, val) {
  const dep = new Dep()
  Object.defineProperty(obj, key, {
    get() {
      if (Dep.target) {
        dep.depend() // 收集当前 Watcher
      }
      return val
    },
    set(newVal) {
      if (newVal === val) return
      val = newVal
      dep.notify() // 通知更新
    }
  })
}
  1. Watcher 初始化
    当组件渲染或计算属性被访问时,创建 Watcher 实例并执行 getter 函数,触发属性的 getter

  2. 依赖关联
    Dep.target 指向当前 Watcher,通过 dep.depend()Watcher 添加到 Dep.subs 中。

数组的处理

对于数组,Vue 通过拦截原生方法(如 pushpop)触发更新,并对数组元素递归执行 observe

const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)
;['push', 'pop', 'shift'].forEach(method => {
  const original = arrayProto[method]
  arrayMethods[method] = function(...args) {
    const result = original.apply(this, args)
    this.__ob__.dep.notify() // 通知更新
    return result
  }
})

Vue 3 的优化

Vue 3 改用 Proxy 实现响应式,依赖收集逻辑类似,但不再需要递归劫持属性,而是按需动态收集:

vue依赖收集实现

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key, receiver) {
      track(target, key) // 依赖收集
      return Reflect.get(target, key, receiver)
    },
    set(target, key, value, receiver) {
      Reflect.set(target, key, value, receiver)
      trigger(target, key) // 触发更新
    }
  })
}

关键点总结

  • 惰性依赖收集:仅在 Watcher 访问属性时建立依赖关系。
  • 精准更新:每个属性维护独立的 Dep,避免不必要的重新渲染。
  • 避免循环依赖:通过 Dep.target 栈管理嵌套 Watcher

标签: vue
分享给朋友:

相关文章

vue实现mvc

vue实现mvc

Vue 实现 MVC 模式 Vue 本身是一个 MVVM(Model-View-ViewModel)框架,但可以通过结构调整实现 MVC(Model-View-Controller)模式。以下是具体实…

vue tag实现

vue tag实现

Vue 标签实现方法 在 Vue 中实现标签功能可以通过多种方式完成,常见场景包括动态标签生成、标签输入框、标签管理等。以下是几种典型实现方案: 动态标签列表渲染 使用 v-for 指令渲染标签数组…

vue实现图册

vue实现图册

Vue实现图册功能 在Vue中实现图册功能通常涉及图片展示、切换、缩放等交互效果。以下是常见的实现方法和关键代码示例: 基础图册组件结构 使用Vue单文件组件构建基础结构: <templat…

vue实现route

vue实现route

Vue 路由实现方法 Vue 中实现路由通常使用 vue-router 库,这是 Vue 官方推荐的路由管理器。以下是具体实现步骤: 安装 vue-router 通过 npm 或 yarn 安装…

vue实现粘贴

vue实现粘贴

Vue 实现粘贴功能的方法 在 Vue 中实现粘贴功能通常涉及监听粘贴事件并处理剪贴板数据。以下是几种常见的实现方式: 监听原生粘贴事件 通过 @paste 指令或原生 addEventListen…

vue实现上传

vue实现上传

Vue 文件上传实现方法 使用 Vue 实现文件上传可以通过原生 HTML5 的 <input type="file"> 元素结合 Vue 的事件处理和数据绑定来实现。 基础实现步骤…