当前位置:首页 > VUE

vue 观察者实现

2026-02-24 06:42:43VUE

Vue 观察者实现原理

Vue 的响应式系统核心基于观察者模式,通过 Object.defineProperty(Vue 2)或 Proxy(Vue 3)实现数据劫持,结合依赖收集和派发更新机制实现数据变化时的自动视图更新。

Vue 2 实现方式

数据劫持 通过 Object.defineProperty 递归遍历对象属性,将属性转为 getter/setter:

function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    get() {
      console.log('读取属性', key);
      return val;
    },
    set(newVal) {
      if (newVal !== val) {
        console.log('设置属性', key);
        val = newVal;
      }
    }
  });
}

依赖收集 每个被观察的数据属性关联一个 Dep 实例(依赖管理器),在 getter 中收集依赖(Watcher),在 setter 中通知更新:

class Dep {
  constructor() {
    this.subs = []; // 存储 Watcher 实例
  }
  addSub(sub) {
    this.subs.push(sub);
  }
  notify() {
    this.subs.forEach(sub => sub.update());
  }
}

function defineReactive(obj, key, val) {
  const dep = new Dep();
  Object.defineProperty(obj, key, {
    get() {
      if (Dep.target) { // 当前 Watcher 实例
        dep.addSub(Dep.target);
      }
      return val;
    },
    set(newVal) {
      if (newVal !== val) {
        val = newVal;
        dep.notify(); // 触发更新
      }
    }
  });
}

Watcher 实现 Watcher 作为观察者,在初始化时触发 getter 以收集依赖:

class Watcher {
  constructor(vm, exp, cb) {
    this.vm = vm;
    this.exp = exp;
    this.cb = cb;
    Dep.target = this; // 标记当前 Watcher
    this.value = this.get(); // 触发 getter 收集依赖
    Dep.target = null;
  }
  get() {
    return this.vm[this.exp]; // 触发数据属性的 getter
  }
  update() {
    const newValue = this.get();
    if (newValue !== this.value) {
      this.cb(newValue);
      this.value = newValue;
    }
  }
}

Vue 3 实现方式

Vue 3 改用 Proxy 实现数据劫持,解决 Vue 2 中无法检测新增属性/数组变化的问题:

vue 观察者实现

Proxy 代理

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); // 触发更新
      return true;
    }
  });
}

依赖管理

const targetMap = new WeakMap(); // 存储所有依赖

function track(target, key) {
  if (!activeEffect) return;
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }
  let dep = depsMap.get(key);
  if (!dep) {
    depsMap.set(key, (dep = new Set()));
  }
  dep.add(activeEffect);
}

function trigger(target, key) {
  const depsMap = targetMap.get(target);
  if (!depsMap) return;
  const effects = depsMap.get(key);
  effects && effects.forEach(effect => effect());
}

Effect 函数 替代 Vue 2 的 Watcher,通过 effect 函数自动执行依赖收集:

vue 观察者实现

let activeEffect = null;

function effect(fn) {
  activeEffect = fn;
  fn(); // 执行时触发 getter 收集依赖
  activeEffect = null;
}

关键差异

  1. 劫持方式

    • Vue 2 使用 Object.defineProperty,需递归遍历对象且无法检测新增属性。
    • Vue 3 使用 Proxy,支持动态属性添加和数组索引修改。
  2. 性能优化

    • Vue 3 的 Proxy 直接代理整个对象,无需递归初始化所有属性。
  3. 依赖追踪

    • Vue 2 通过 Dep/Watcher 层级结构管理依赖。
    • Vue 3 通过 WeakMap/Map/Set 实现更细粒度的依赖关系。

标签: 观察者vue
分享给朋友:

相关文章

jquery实现vue

jquery实现vue

jQuery 和 Vue.js 是两种不同理念的前端工具,jQuery 以 DOM 操作和事件驱动为核心,而 Vue.js 是数据驱动的现代化框架。如果想用 jQuery 实现类似 Vue 的功能(如…

vue实现心电图

vue实现心电图

Vue 实现心电图效果 在 Vue 中实现心电图效果通常需要结合 Canvas 或 SVG 进行动态绘图,模拟心电图数据的实时变化。以下是两种实现方式的核心思路和代码示例: 使用 Canvas 绘制…

vue逻辑实现怎么实现

vue逻辑实现怎么实现

Vue 逻辑实现方法 Vue 的逻辑实现主要通过组件化、响应式数据、计算属性、方法、生命周期钩子等方式完成。以下是一些核心实现方法: 数据驱动与响应式 在 Vue 中,通过 data 选项定义响应式…

vue实现登录认证

vue实现登录认证

Vue 登录认证实现方法 使用 Vue Router 和 Vuex 管理登录状态 在 Vue 项目中,通常使用 Vue Router 进行路由管理,Vuex 进行状态管理。登录认证的核心是验证用户身份…

vue实现word在线

vue实现word在线

Vue 实现 Word 在线编辑与预览 方案一:使用 docx.js 与前端解析 安装依赖库 docx 和 file-saver,用于生成和下载 Word 文件: npm install docx…

vue实现输入地址

vue实现输入地址

Vue 实现输入地址功能 在 Vue 中实现输入地址功能,可以通过结合表单输入、地图 API(如高德、百度或 Google Maps)以及地址自动补全等方式完成。以下是几种常见方法: 使用高德地图…