Vue2与Vue3实现响应式的原理

21 篇文章 0 订阅
4 篇文章 0 订阅
本文深入探讨Vue的响应式原理,从2.x的Object.defineProperty()实现数据劫持和观察者模式,到3.x引入的window.Proxy和Reflect.defineProperty(),展示了Vue如何通过代理对象实现更高效、全面的响应式机制。同时,介绍了如何在Vue2中处理数组响应式以及在Vue3中如何监听属性的删除。
摘要由CSDN通过智能技术生成

Vue2.x 实现响应式

Vue响应式原理?为什么data数据改变页面也会发生变化?

数据劫持与观察者模式是实现响应式,核心API Object.defineProperty()

Object.definedProperty()可以做数据劫持和数据代理,从而实现Vue响应式
<script>
    // 将对象类型的数据变成响应式的数据,需要进行深度监听
    const data = {
      name: "zhangsan",
      age: 12,
      friends: {
        name: "lisi",
        age: 20
      },
      arr1: ["aaa", 'bbb', 111]
    }

    // 对于响应式的数据不能直接删除或者添加一个数据
    // 需要借助vue.set 和 vue.delete

    // vue2对数组的原型上的方法进行了二次封装,可以让数组的一些方法实现响应式
    const oldArrayProto = Array.prototype
    const newArrayProto = Object.create(oldArrayProto) //newArratProto对象的原型上添加上数组的原型上的方法
    // console.log(newArratProto);
    const arrMethod = ["pop", 'push', 'unshift', 'splice', 'indexOf', 'includes']
    arrMethod.forEach(item => {
      newArrayProto[item] = function () {
        oldArrayProto[item].call(this, ...arguments) //调用数组的原型上的方法
      }
    })

    observer(data) //可以将data的数据变成响应式的

    // 观察者模式:观察值是否是引用类型的数据 
    function observer(value) {
      if (!(value instanceof Object) || value === null) {
        return value
      }
      if (value instanceof Array) {
        value.__proto__ = newArrayProto
      }
      for (let key in value) {
        defineReactive(value, key, value[key])
      }
    }
    // 数据劫持
    function defineReactive(obj, key, val) {
      observer(val)
      Object.defineProperty(obj, key, {
        get() {
          return val1
        },
        set(newVal) {
          observer(val)
          console.log("xxx");
          if (newVal !== val) {
            val = newVal
            console.log(newVal, "视图发生更新");
          }
        }
      })
    }
    // data.name = "hhh"
    // data.friends.name = "xxx"
    // data.age = { count: 0 }
    // data.age.count = 100
    // console.log(data.arr1.push("xxx"));
    // console.log(data.arr1);
  </script>

Vue3.x 实现响应式

vue3底层实现响应式:window.Proxy[代理对象] + window.Reflect.defineProperty() 【反射对象】
<script>
    let person = {
      name: "zhangsan",
      age: 12,
      // sex: "男"
    }

    // 模拟Vue2数据响应式:vue2实现响应式过程比较复杂,而且监听不到对象属性的删除,
    /* let sex = "男"
    Object.defineProperty(person, "sex", {
      get() { // 只能监听对象属性的获取
        return sex
      },
      set(newVal) { //只能监听到对象属性的修改
        sex = newVal
      }
    }) */

    // vue3底层实现响应式:window.Proxy[代理对象] + window.Reflect.defineProperty() 【反射对象】
    const p = new Proxy(person, {
      // get可以监听到属性的获取
      //get第一个参数:是当前代理对象p 代理 的源对象【Proxy的第一个参数】; 第二个参数:是当前是使用代理对象访问到的属性名
      get(target, propName) {
        console.log("读取了p上的属性:", propName);
        // return target[propName]
        return Reflect.get(target, propName)
      },
      // set可以监听到属性的变化
      // set第一个参数:是当前代理对象p 代理 的源对象【Proxy的第一个参数】; 第二个参数:是当前是使用代理对象访问到的属性名;第三个参数:新的值
      set(target, propName, newVal) {
        console.log("修改了p上的属性:", propName);
        // target[propName] = newVal
        Reflect.set(target, propName, newVal)
      },
      // 监听属性删除:第一个参数:是当前代理对象p 代理 的源对象【Proxy的第一个参数】; 第二个参数:是当前是使用代理对象访问到的属性名;
      deleteProperty(target, propName) {
        console.log("删除p上的属性:", propName);
        // return delete target[propName] //删除成功就返回true 删除失败就返回false
        return Reflect.deleteProperty(target, propName)
      }
    }) // p代理对象可以映射一个对象[对p进行操作,就相当于对对象进行操作,p代理对象可以检测到对代理对象的任何操作]
    console.log(p);

  </script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iku_ki

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值