Reactivity方法的实现


reactive方法会将对象变成 proxy 对象

基本实现

  • reactivity.ts
import { isObject } from "@vue/shared"

export function reactive(target: object) {
  // reactive 只能处理对象类型的数据,不是对象不处理
  if (!isObject(target)) return target

  const proxy = new Proxy(target, muableHandlers) // 没有代理过创建代理

  return proxy
}
  • @vue/shared
export const isObject = (value: unknown): value is Record<any, any> => {
  // return Object.prototype.toString.call(value) === '[object Object]';
  return value !== null && typeof value === "object"
}
  • handler.ts
export const muableHandlers: ProxyHandler<object> = {
  // receiver相当于代理对象
  get(target, key, receiver) {
    //取值的时候,让属性和effect产生关系
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    //设置的时候,让属性对应的effect执行
    Reflect.set(target, key, value, receiver)
    return true
  },
}

增加缓冲

问题: 同一个对象被代理多次

import { reactive } from "./reactivity.js"
const obj = { name: "ghx", age: 22 }
const state1 = reactive(obj)
const state2 = reactive(obj)
console.log("state=>", state1 === state2) //false

优化:采用映射表

  • reactivity.ts
import { isObject } from "@vue/shared";
import { muableHandlers } from "./handler";

+ const reactiveMap = new WeakMap()
export function reactive(target: object) {
  // reactive 只能处理对象类型的数据,不是对象不处理
  if (!isObject(target)) return target

+  // 缓存可以采用映射表 {{target} -> proxy}
+  let existingProxy = reactiveMap.get(target)// 看一下这个对象是否有被代理过
+  if (existingProxy) return existingProxy// 代理过直接返回

  //防止对象重复被代理
  if (target[ReactiveFlags.IS_REACTIVE]) {
    return target;
  }

  const proxy = new Proxy(target, muableHandlers)// 没有代理过创建代理
+  reactiveMap.set(target, proxy) // 缓存代理结果
  return proxy
}

唯一标识

问题:把已经代理过的对象继续代理

import { reactive } from "./reactivity.js"
const obj = { name: "ghx", age: 22 }
const state1 = reactive(obj)
const state2 = reactive(state1)
console.log("state=>", state1 === state2) //false

以前的方案

  • 在 vue3.0 的时候 会创造一个反向映射表 {代理的结果 -》 原内容}】

优化: 采用唯一标识

reactivity.ts

import { isObject } from "@vue/shared";
import { muableHandlers } from "./handler";

+export const enum ReactiveFlags { // 对象
+  IS_REACTIVE = "__v_isReactive",
+}
const reactiveMap = new WeakMap()
export function reactive(target: object) {
  // reactive 只能处理对象类型的数据,不是对象不处理
  if (!isObject(target)) return target

  // 缓存可以采用映射表 target -> proxy
  let existingProxy = reactiveMap.get(target)// 看一下这个对象是否有被代理过
  if (existingProxy) return existingProxy// 代理过直接返回

+  //防止对象重复被代理
+  if (target[ReactiveFlags.IS_REACTIVE]) {
+    return target;
+  }

  const proxy = new Proxy(target, muableHandlers)// 没有代理过创建代理
  reactiveMap.set(target, proxy) // 缓存代理结果
  return proxy
}

handler.ts

+import { ReactiveFlags } from "./reactivity";

export const muableHandlers: ProxyHandler<object> = {
  // receiver相当于代理对象
  get(target, key, receiver) {
    //取值的时候,让属性和effect产生关系
+    if (key === ReactiveFlags.IS_REACTIVE) {
+      return true;
+    }
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    //设置的时候,让属性对应的effect执行
    Reflect.set(target, key, value, receiver)
    return true
  },
}

文章作者: 高红翔
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 高红翔 !
  目录