当前位置:首页 > 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 方法中,通知所有依赖进行更新。

    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实现单选

Vue 实现单选功能 在 Vue 中实现单选功能可以通过多种方式完成,以下是几种常见的方法: 使用 v-model 绑定单选按钮 通过 v-model 绑定一个变量,可以实现单选功能。单选按钮的 v…

vue前端实现打印功能

vue前端实现打印功能

使用Vue实现前端打印功能 在Vue项目中实现打印功能可以通过多种方式完成,以下是几种常见的方法: 使用window.print()方法 这是最简单的打印方式,直接调用浏览器的打印功能。 me…

vue实现一个标签选择

vue实现一个标签选择

Vue 标签选择组件实现 基础实现 使用 Vue 的 v-for 和 v-model 指令可以快速实现标签选择功能: <template> <div class="tag-s…

vue实现发表

vue实现发表

Vue 实现发表功能 在 Vue 中实现发表功能通常涉及表单处理、数据绑定和网络请求。以下是实现步骤和代码示例: 表单设计与数据绑定 创建一个表单用于输入发表内容,使用 v-model 进行数据双向…

vue实现store

vue实现store

Vue 实现 Store 在 Vue 中,可以通过 Vuex 或 Pinia 实现全局状态管理(Store)。以下是两种主流方案的实现方法。 使用 Vuex 实现 Store Vuex 是 Vu…

vue实现轮询

vue实现轮询

实现轮询的基本方法 在Vue中实现轮询可以通过setInterval或setTimeout配合递归调用完成。轮询通常用于定期向服务器请求数据更新。 使用setInterval的简单示例: da…