实现isReactive和isReadonly
isReactive实现
先上测试用例(其实这个测试用例也是reactive.spec.ts中追加的两个):
import { isReactive, reactive } from "../reactive"
describe('reactive',()=>{
it('happy path',()=>{
const original = {foo:1}
const observed = reactive(original)
expect(observed).not.toBe(original)
expect(observed.foo).toBe(1)
expect(isReactive(observed)).toBe(true)
expect(isReactive(original)).toBe(false)
})
})
实现:
1 reactive.ts中导出isReactive方法
2 利用isReactive传入的对象,调用对象中特定设置的一个属性__v_isReactive,如果这个对象是响应式对象,就会走get函数
3 我们可以在get函数中判断key值,如果为__v_isReactive的话,就返回他不是readonly
优化
对于这种__v_isReactive属性,我们可以使用枚举,让我们在别的地方降低书写错误
修改如下
isReadonly实现
有了isReactive的实现,那isReadonly也就水到渠成了,测试案例
实现上基本和isReactive一样
reactive.ts
最终:
reactive.ts代码
import { mutableHandlers, readonlyHandlers } from "./baseHandlers"
export const enum ReactiveFlags {
IS_REACTIVE = "__v_isReactive",
IS_READONLY = "__v_isReadonly"
}
export function reactive(raw){
return createReactiveObject(raw,mutableHandlers)
}
export function readonly(raw){
return createReactiveObject(raw,readonlyHandlers)
}
export function isReactive(value){
return !!value[ReactiveFlags.IS_REACTIVE]
}
export function isReadonly(value){
return !!value[ReactiveFlags.IS_READONLY]
}
function createReactiveObject(target,baseHandlers){
return new Proxy(target,baseHandlers)
}
baseHandlers.ts
import { track, trigger } from "./effect"
import { ReactiveFlags } from "./reactive"
const get = createGetter()
const set = createSetter()
const readonlyGet = createGetter(true)
function createGetter(isReadonly = false){
return function get(target,key){
const res = Reflect.get(target,key)
if(key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly
}
if(key === ReactiveFlags.IS_READONLY) {
return isReadonly
}
if(!isReadonly) {
track(target,key)
}
return res
}
}
function createSetter() {
return function set(target,key,value){
const res = Reflect.set(target,key,value)
trigger(target,key)
return res
}
}
export const mutableHandlers = {
get:get,
set:set
}
export const readonlyHandlers = {
get:readonlyGet,
set(target,key,value){
console.warn(`key:${key} set 失败 因为 target 是readonly`,target)
return true
}
}