实现vue3源码-isReactive & isReadonly & isProxy

146 阅读2分钟

isReactive和isReadonly它俩的实现方式如出一辙,一模一样可以说,那就实现下吧

isReactive

isReadonly

isProxy

结语

isReactive

这个是用来判断是不是reactive的,实现起来也是非常简单几行代码就可以搞定

首先呢,这是我们的期望结果

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)
    })
})

代码很简单,实现更简单,我们只需要在get里面做判断就够了,函数内返回结果也有兜底和注释

reactive.ts

export const enum ReactiveFlags {
    IS_REACTIVE = '__v_isReactive'
}

export function isReactive(value) {
    // 不是 Proxy 就不会调用 get,得到的就是 undefined,所以双重取反布尔值就行
    return !!value[ReactiveFlags.IS_REACTIVE] 
}

baseHandlers.ts

function createGetter(isReadonly = false) {
    return function get(target, key) {
        const res = Reflect.get(target, key)

        // 判断是不是 reactive
        if(key === ReactiveFlags.IS_REACTIVE) {
            return !isReadonly
        }
        
        // 依赖收集
        // 抽离公共,判断是否需要收集依赖<readonly>
        !isReadonly && track(target, key)
        return res
    }
}

isReadonly

同理,实现方法与 isReactive 高度一致

reactive.ts

export const enum ReactiveFlags {
    IS_READONLY = '__v_isReadonly'
}

export function isReadonly(value) {
    // 不是 Proxy 就不会调用 get,得到的就是 undefined,所以双重取反布尔值就行
    return !!value[ReactiveFlags.IS_READONLY] 
}

baseHandlers.ts

function createGetter(isReadonly = false) {
    return function get(target, key) {
        const res = Reflect.get(target, key)

        // 判断是不是 readonly
        if(key === ReactiveFlags.IS_READONLY) {
            return isReadonly
        }
        
        // 依赖收集
        // 抽离公共,判断是否需要收集依赖<readonly>
        !isReadonly && track(target, key)
        return res
    }
}

reactive.ts

export const enum ReactiveFlags {
    IS_REACTIVE = '__v_isReactive',
    IS_READONLY = '__v_isReadonly'
}

export function isReactive(value) {
    // 不是 Proxy 就不会调用 get,得到的就是 undefined,所以双重取反布尔值就行
    return !!value[ReactiveFlags.IS_REACTIVE] 
}

export function isReadonly(value) {
    // 不是 Proxy 就不会调用 get,得到的就是 undefined,所以双重取反布尔值就行
    return !!value[ReactiveFlags.IS_READONLY]
}

baseHandlers.ts

function createGetter(isReadonly = false) {
    return function get(target, key) {
        const res = Reflect.get(target, key)

        // 判断是不是 reactive
        if(key === ReactiveFlags.IS_REACTIVE) {
            return !isReadonly
        } else if(key === ReactiveFlags.IS_READONLY) {
            return isReadonly
        }
        
        // 依赖收集
        // 抽离公共,判断是否需要收集依赖<readonly>
        !isReadonly && track(target, key)
        return res
    }
}

补充

isProxy

这个太简单了就不单开一章了,其实就是用isReactive & isReadonly它俩来实现的

export function isProxy(value) {
    return isReactive(value) || isReadonly(value)
}

结语

它俩的实现方式高度一致,实现方法也是非常简单,有些地方并没有做到天衣无缝,很多判断也没做,但是这是最基本的实现方式,也可以作为一个简单的参考