1、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
},
}
思考 为什么要用 Reflect
let person = {
name: "John Doe",
age: 20,
get aliasName() {
return "**" + this.name
},
set aliasName(value) {
this.name = value
},
}
const proxyPerson = new Proxy(person, {
get(target, key, receiver) {
console.log("获取" + key)
// return target[key]
//为了解决this问题,增加一层映射
return Reflect.get(target, key)
},
set(target, key, value, receiver) {
console.log("通知页面" + key + "改变了")
// return (target[key] = value)
return Reflect.set(target, key, value, receiver)
},
})
console.log("=proxyPerson.aliasName>", proxyPerson.aliasName)
proxyPerson.name = "ghx"
- 为了解决 this 问题 增加一层映射,放在对象是 getter 取值 里面有 this,然后 getter 里面的 this 取值没有被依赖收集