当前位置:首页 > VUE

vue响应式实现

2026-01-06 23:20:26VUE

Vue 响应式实现原理

Vue 的响应式系统基于 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)实现,通过数据劫持和依赖收集实现数据变化时的自动更新。

Vue 2.x 的实现方式

Vue 2.x 使用 Object.defineProperty 对对象的属性进行劫持,通过 gettersetter 监听数据变化。

function defineReactive(obj, key, val) {
  // 递归处理嵌套对象
  observe(val);

  Object.defineProperty(obj, key, {
    get() {
      console.log(`get ${key}: ${val}`);
      return val;
    },
    set(newVal) {
      if (newVal !== val) {
        console.log(`set ${key}: ${newVal}`);
        observe(newVal); // 处理新值为对象的情况
        val = newVal;
      }
    }
  });
}

function observe(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return;
  }
  Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key]);
  });
}

依赖收集通过 DepWatcher 实现:

class Dep {
  constructor() {
    this.subs = [];
  }
  addSub(sub) {
    this.subs.push(sub);
  }
  notify() {
    this.subs.forEach(sub => sub.update());
  }
}

class Watcher {
  constructor(vm, key, cb) {
    this.vm = vm;
    this.key = key;
    this.cb = cb;
    Dep.target = this;
    this.vm[this.key]; // 触发 getter,收集依赖
    Dep.target = null;
  }
  update() {
    this.cb.call(this.vm, this.vm[this.key]);
  }
}

Vue 3.x 的实现方式

Vue 3.x 改用 Proxy 实现响应式,解决了 Object.defineProperty 的局限性(如数组监听、新增属性等)。

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key, receiver) {
      console.log(`get ${key}`);
      return Reflect.get(target, key, receiver);
    },
    set(target, key, value, receiver) {
      console.log(`set ${key}: ${value}`);
      return Reflect.set(target, key, value, receiver);
    }
  });
}

依赖收集和触发更新通过 effecttrack/trigger 实现:

let activeEffect;
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 dep = depsMap.get(key);
  if (dep) {
    dep.forEach(effect => effect());
  }
}

function effect(fn) {
  activeEffect = fn;
  fn();
  activeEffect = undefined;
}

响应式系统的核心流程

数据劫持:通过 Object.definePropertyProxy 拦截对象的读写操作。

依赖收集:在属性被访问时(get),收集当前正在执行的依赖(如组件的渲染函数)。

触发更新:在属性被修改时(set),通知所有相关依赖进行更新。

数组的特殊处理

Vue 2.x 中通过重写数组的变异方法(如 pushpop)实现响应式:

const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);

['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(method => {
  const original = arrayProto[method];
  arrayMethods[method] = function(...args) {
    const result = original.apply(this, args);
    const ob = this.__ob__;
    ob.dep.notify();
    return result;
  };
});

Vue 3.x 的 Proxy 可以直接监听数组变化,无需特殊处理。

响应式系统的优化

Vue 3.x 的响应式系统相比 Vue 2.x 有以下改进:

性能更好:Proxy 是语言层面的支持,比 Object.defineProperty 更高效。

功能更强大:可以检测到属性的添加和删除,以及数组索引和长度的变化。

代码更简洁:无需像 Vue 2.x 那样对数组进行特殊处理。

vue响应式实现

标签: vue
分享给朋友:

相关文章

vue实现聊天

vue实现聊天

Vue实现聊天功能 基础项目结构搭建 使用Vue CLI或Vite创建项目,安装必要依赖如socket.io-client或axios(根据通信方式选择)。核心组件通常包括: ChatWindow.…

vue实现预览

vue实现预览

Vue实现文件预览的方法 使用Vue实现文件预览功能可以通过多种方式完成,具体取决于文件类型(图片、PDF、视频等)。以下是几种常见文件类型的实现方案。 图片预览 通过<input type=…

vue循环数组实现

vue循环数组实现

vue循环数组的实现方法 在Vue中循环数组主要通过v-for指令实现,以下是几种常见用法: 基本数组循环 使用v-for指令遍历数组,可以通过(item, index)的语法获取当前项和索引值:…

vue实现按钮刷新

vue实现按钮刷新

Vue 实现按钮刷新功能 在 Vue 中实现按钮刷新功能可以通过多种方式实现,具体取决于刷新需求是局部刷新还是全局刷新。以下是几种常见的方法: 使用 window.location.reload()…

vue实现横向导航

vue实现横向导航

vue实现横向导航的方法 使用Flex布局实现横向导航 在Vue中可以通过Flex布局快速实现横向导航。创建一个组件,使用display: flex和flex-direction: row属性使导航项…

用vue实现搜索查询

用vue实现搜索查询

实现搜索查询的基本思路 在Vue中实现搜索查询功能通常涉及以下几个核心部分:数据绑定、事件监听、过滤逻辑和UI反馈。以下是一个完整的实现方案。 数据绑定与输入框 创建一个Vue组件,包含一个输入框用…