MST

星途 面试题库

面试题:深入剖析Vue响应式数据更新机制中的依赖收集与派发更新过程

请详细描述Vue响应式数据更新机制中,依赖收集(dependency collection)是如何实现的,以及当数据发生变化时,派发更新(dispatch update)的具体流程和涉及到的关键对象与方法。
16.2万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

依赖收集的实现

  1. Object.defineProperty
    • 在Vue2.x中,通过Object.defineProperty来劫持对象的属性访问和赋值操作。例如:
    const data = { name: 'John' };
    Object.defineProperty(data, 'name', {
      get() {
        // 依赖收集逻辑
        console.log('获取name属性');
        return value;
      },
      set(newValue) {
        if (newValue!== value) {
          value = newValue;
          // 派发更新逻辑
          console.log('name属性值更新');
        }
      }
    });
    
    • 当访问属性时,会触发get方法,在get方法中进行依赖收集。
  2. Dep类
    • Vue内部有一个Dep类,它代表一个依赖管理器。每个被劫持的属性都对应一个Dep实例。
    • Dep类有一个subs数组,用来存储依赖(Watcher实例)。例如:
    class Dep {
      constructor() {
        this.subs = [];
      }
      addSub(sub) {
        this.subs.push(sub);
      }
      notify() {
        this.subs.forEach(sub => sub.update());
      }
    }
    
  3. Watcher类
    • Watcher代表一个观察者,它实例化时会将自身添加到当前正在读取的属性的Dep中。例如:
    class Watcher {
      constructor(vm, expOrFn, cb) {
        this.vm = vm;
        this.cb = cb;
        // 将当前Watcher实例设置为全局唯一的Watcher实例
        Dep.target = this;
        // 读取数据,触发getter进行依赖收集
        this.get();
        Dep.target = null;
      }
      get() {
        const vm = this.vm;
        const value = this.getter.call(vm, vm);
        return value;
      }
      update() {
        const oldValue = this.value;
        this.value = this.get();
        this.cb.call(this.vm, this.value, oldValue);
      }
    }
    
    • 当一个Watcher实例读取某个数据属性时,该属性的Dep会将这个Watcher添加到subs数组中,完成依赖收集。

派发更新的流程

  1. 数据变化触发setter
    • 当数据发生变化,例如data.name = 'Jane',会触发set方法。
  2. Dep.notify
    • set方法中,会调用对应的Dep实例的notify方法。例如:
    set(newValue) {
      if (newValue!== value) {
        value = newValue;
        dep.notify();
      }
    }
    
  3. Watcher.update
    • Depnotify方法会遍历subs数组,调用每个Watcherupdate方法。
    • Watcherupdate方法会重新获取数据,并执行回调函数(例如更新DOM等操作)。

关键对象与方法

  1. Dep类
    • 关键方法
      • addSub:用于添加依赖(Watcher实例)到subs数组。
      • notify:当数据变化时,通知所有依赖(Watcher实例)进行更新。
  2. Watcher类
    • 关键方法
      • update:重新获取数据,并执行回调函数,实现更新操作。
  3. Object.defineProperty
    • 用于劫持对象属性的访问和赋值操作,是实现依赖收集和派发更新的基础。在Vue3.x中,使用ProxyReflect来替代Object.defineProperty,但核心的依赖收集和派发更新原理类似。