reactive源码解析

vue3源码解析——ref和reactive定义响应式的区别-LMLPHP

vue3源码解析——ref和reactive定义响应式的区别-LMLPHP

proxy是怎么代理的?

  let handler = {
    //拦截整个对象,访问对象的属性时get拦截器触发
    get(target, key) {
      let value = target[key];
      if (typeof value === "object") {
        //如果访问的对象属性还是对象,进行递归
        return new Proxy(value, handler);
      }
      return value;
    },
    //拦截整个对象,当修改对象的属性的时候set拦截器会触发
    set(target, key, value) {
      target[key] = value;
    },
  };
  function reactive(target) {
    return new Proxy(target, handler);
  }

  let obj = { name: "jw", age: 30, n: [1, 2, 3, 4, 5] };
  //拿到obj的代理对象proxyObj
  const proxyObj = reactive(obj);
  //不访问obj,访问代理对象proxyObj
  console.log(proxyObj.name); //触发get拦截器
  proxyObj.age = 31; //触发set拦截器
  proxyObj.name = 100; //设置一个不存在的属性
  • get(target, property, receiver):拦截对象属性的读取操作,当访问代理对象的属性时会触发该方法。
  • set(target, property, value, receiver):拦截对象属性的设置操作,当给代理对象的属性赋值时会触发该方法。

ref源码原理

为什么ref定义后的对象可以通过.value 访问和设置数据?

get 和 set 属性是一种在类中定义属性的方式,可以用来实现类的属性的读取和写入操作。基本语法如下:

class MyClass {
  private _propertyName: any;
  get propertyName(): any {
    console.log("读取数据,自动进入get方法");
    return this._propertyName;
  }
  set propertyName(value: any) {
    this._propertyName = value;
    console.log("更新数据,自动进入set方法");
  }
}

在上面的例子中,propertyName 是一个类的属性,它使用 get 和 set 属性定义在 MyClass 类中。在类的外部,可以使用点操作符来读取和写入 propertyName 属性,例如:

const myObject = new MyClass();
myObject.propertyName = 'hello';//更新
console.log(myObject.propertyName); //访问

执行结果

vue3源码解析——ref和reactive定义响应式的区别-LMLPHP

当在类的外部读取 propertyName 属性时,会调用 propertyName 的 get 属性,返回 _propertyName 的值。当在类的外部写入 propertyName 属性时,会调用 propertyName 的 set 属性,将值赋给 _propertyName 属性。

为什么在类里这样写可以触发get和set呢?

var MyClass = /** @class */ (function () {
    function MyClass() {
    }
    Object.defineProperty(MyClass.prototype, "propertyName", {
        get: function () {
            console.log("读取数据,自动进入get方法");
            return this._propertyName;
        },
        set: function (value) {
            this._propertyName = value;
            console.log("更新数据,自动进入set方法");
        },
        enumerable: false,
        configurable: true
    });
    return MyClass;
}());
var myObject = new MyClass();
myObject.propertyName = "hello";
console.log(myObject.propertyName);

vue3中ref实现

vue3源码解析——ref和reactive定义响应式的区别-LMLPHP

vue3源码解析——ref和reactive定义响应式的区别-LMLPHP

toReactive方法做了什么?

vue3源码解析——ref和reactive定义响应式的区别-LMLPHP

 思考:为什么你更习惯使用ref而不是reactive?

  1. 简单性ref 提供了一种简单的方式来定义响应式对象,只需传入初始值即可。相比之下,reactive 需要将整个对象传入,稍显繁琐。对于单个变量或简单数据,使用 ref 更加直观和方便。

  2. 透明性ref 返回的是一个包装过的对象,可以通过 .value 访问其值,这种包装使得数据访问更加明确和直观。而 reactive 返回的是原始对象,需要通过代理访问属性,有时会增加代码的复杂性。(复杂的代码谁想写啊)

  3. 性能:在某些情况下,ref 比 reactive 更高效。因为 ref 包装的是基本类型数据,而 reactive 包装的是对象,对于简单数据类型,ref 的性能可能更好。

  4. 推荐度:Vue 3 官方文档和社区更倾向于推荐使用 ref,因为它更简单、更直观,适用于大多数场景。而 reactive 更适合处理复杂的对象或数据结构。

03-30 04:50