当前位置:首页 > VUE

vue数据劫持实现

2026-01-14 05:23:10VUE

Vue 数据劫持实现原理

Vue 的数据劫持主要通过 Object.definePropertyProxy 实现,用于监听对象属性的变化并触发更新。以下是核心实现方式:

基于 Object.defineProperty

  1. 劫持对象属性 通过 Object.defineProperty 重写对象的 getset 方法,在属性被访问或修改时触发依赖收集和更新通知。

    function defineReactive(obj, key, val) {
      Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get() {
          console.log(`读取属性 ${key}`);
          return val;
        },
        set(newVal) {
          if (newVal === val) return;
          console.log(`更新属性 ${key},新值: ${newVal}`);
          val = newVal;
        }
      });
    }
    
    const data = { name: 'Vue' };
    defineReactive(data, 'name', data.name);
  2. 递归劫持嵌套对象 需要递归处理对象中的嵌套属性,确保所有层级的数据均可被监听。

    function observe(obj) {
      if (typeof obj !== 'object' || obj === null) return;
      Object.keys(obj).forEach(key => {
        defineReactive(obj, key, obj[key]);
        observe(obj[key]); // 递归处理嵌套对象
      });
    }
  3. 数组方法劫持 由于 Object.defineProperty 无法直接监听数组变化,需重写数组的变异方法(如 pushpop)。

    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);
        console.log(`数组方法 ${method} 被调用`);
        return result;
      };
    });

基于 Proxy(Vue 3)

Vue 3 使用 Proxy 替代 Object.defineProperty,可直接监听对象和数组的变化,无需递归或重写方法。

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      console.log(`读取属性 ${key}`);
      return Reflect.get(target, key);
    },
    set(target, key, val) {
      if (target[key] === val) return true;
      console.log(`更新属性 ${key},新值: ${val}`);
      return Reflect.set(target, key, val);
    }
  });
}

const data = reactive({ name: 'Vue 3' });

依赖收集与派发更新

  1. 依赖收集get 方法中,将当前属性的依赖(如 Watcher)存储到全局的依赖收集器(Dep)中。

    class Dep {
      constructor() {
        this.subscribers = new Set();
      }
      depend() {
        if (activeEffect) this.subscribers.add(activeEffect);
      }
      notify() {
        this.subscribers.forEach(effect => effect());
      }
    }
  2. 派发更新set 方法中,通知所有依赖进行更新。

    vue数据劫持实现

    function defineReactive(obj, key, val) {
      const dep = new Dep();
      Object.defineProperty(obj, key, {
        get() {
          dep.depend(); // 收集依赖
          return val;
        },
        set(newVal) {
          val = newVal;
          dep.notify(); // 触发更新
        }
      });
    }

总结

  • Vue 2:通过 Object.defineProperty 递归劫持对象属性,重写数组方法实现监听。
  • Vue 3:使用 Proxy 直接代理对象,简化监听逻辑,性能更优。
  • 依赖收集和派发更新机制确保数据变化时视图自动同步。

标签: 数据vue
分享给朋友:

相关文章

vue实现文章锚点定位

vue实现文章锚点定位

实现文章锚点定位的方法 在Vue中实现文章锚点定位可以通过多种方式完成,以下是几种常见的方法: 使用原生HTML锚点 通过HTML的id属性和<a>标签的href属性实现锚点跳转。在Vu…

vue SSG实现

vue SSG实现

Vue SSG 实现方法 Vue 的静态站点生成(SSG)可以通过多种工具和框架实现,以下是几种常见的方法: 使用 VuePress VuePress 是一个基于 Vue 的静态站点生成器,适合文档…

实现简易vue

实现简易vue

实现简易 Vue 的核心思路 Vue 的核心功能包括数据响应式、模板编译和虚拟 DOM。以下是一个简易实现方案,涵盖核心功能模块。 数据响应式系统 通过 Object.defineProperty…

vue实现数组

vue实现数组

Vue 实现数组操作的方法 在 Vue 中,数组的操作需要特别注意响应式的问题。Vue 提供了一些方法来确保数组的变动能够触发视图更新。 响应式数组方法 Vue 对以下数组方法进行了封装,确保它们能…

vue实现答辩

vue实现答辩

Vue 实现答辩系统的关键步骤 项目初始化与配置 使用 Vue CLI 或 Vite 创建项目,安装 Vue Router 管理路由,Pinia/Vuex 进行状态管理。配置 ESLint 和 Pre…

vue实现swiper

vue实现swiper

Vue 中实现 Swiper 的方法 安装 Swiper 依赖 在 Vue 项目中安装 Swiper 和相关依赖: npm install swiper vue-awesome-swiper 全局引…