vue3源码学习(二) reactive

77 阅读1分钟

reactive

  • 如果不是一个对象的话就返回了
  • vue3 用的是 proxy 来做代理,不用再去重写数组的方法
  • 也不用递归遍历对象进行数据劫持增加get、set方法所以性能好了很多

reactive/src/reactive.ts

import { isObject } from "@vue/shared";
import { MutableReactiveHandler } from "./baseHandlers";

function createReactiveObject(target) {
  // 如果不是对象的话 就返回
  if (!isObject) {
    return target;
  }
  const proxy = new Proxy(target, MutableReactiveHandler);
  return proxy;
}
export function reactive(target) {
  return createReactiveObject(target);
}

reactive/src/baseHandlers.ts

export const MutableReactiveHandler = {
  get(target, key, receiver) {
    const res = Reflect.get(target, key, receiver);
    return res;
  },
  set(target, key, value, receiver) {
    const result = Reflect.set(target, key, value, receiver);
    return result;
  },
};

如果 reactive 传入的对象已经被代理了怎么办?

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>vue3</title>
  </head>
  <body>
    <script type="module">
      import { reactive } from "./reactivity.js";
      const data = { name: "aa", age: "bb" };
      const state = reactive(data);
      const state1 = reactive(data);
    </script>
  </body>
</html>

就是准备一个 Map 去记录当前这个 target 是否被代理过

reactive/src/reactive.ts

import { isObject } from "@vue/shared";
import { MutableReactiveHandler } from "./baseHandlers";

const proxyMap = new WeakMap();

function createReactiveObject(target) {
  // 如果不是对象的话 就返回
  if (!isObject) {
    return target;
  }

  // 如果属性被代理过的处理
  const existingProxy = proxyMap.get(target);
  if (existingProxy) {
    return target;
  }
  const proxy = new Proxy(target, MutableReactiveHandler);
  // 代理完成之后放到map上
  proxyMap.set(target, proxy);
  return proxy;
}
export function reactive(target) {
  return createReactiveObject(target);
}

如果传入的是代理的对象怎么办?

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>vue3</title>
  </head>
  <body>
    <script type="module">
      import { reactive } from "./reactivity.js";
      const data = { name: "aa", age: "bb" };
      const state = reactive(data);
      // 代理过之后再重新代理
      const state1 = reactive(data)
      // 当传入的是代理之后的对象怎么办
      const state2 = reactive(state);
    </script>
  </body>
</html>

reactive/src/reactive.ts


export const enum ReactiveFlags {
  IS_REACTIVE = "__v_isReactive",
}

function createReactiveObject(target) {
  ...
  // 只有代理过才可能走MutableReactiveHandler中的get方法
  // 普通对象相当于取值 只能是undefined 就不会走这个判断
  if (target[ReactiveFlags.IS_REACTIVE]) {
    return target;
  }
  ...
}
...

reactive/src/baseHandlers.ts

export const MutableReactiveHandler = {
  get(target, key, receiver) {
    // 判断是否被代理过
    if (key == ReactiveFlags.IS_REACTIVE) {
      return true;
    }
    ...
  },
  ...
};