10、带你一步步实现vue3源码之isReactive&isReadonly

171 阅读2分钟

isReadonly和isReadonly

前面我们已经实现了reactivereadonly,这一节,我们来实现两个方法isReactiveisReadonly,用来判断一个对象是否是reactivereadonly对象。

编写测试

首先,我们先来完善一下测试用例

编写isReactive测试

// src/reactivity/tests/reactive.spec.ts
import {reactive, isReactive} from '../reactive'
describe("reactive", () => {
  it("happy path", () => {
    ...
    expect(isReactive(obj)).toBe(true)
    expect(isReactive(origin)).toBe(false)
  })
})

编写isReadonly测试

// src/reactivity/tests/readonly.spec.ts
describe("readonly", () => {
  it("happy path", () => {
    ...
    expect(isReadonly(wrapped)).toBe(true)
  })
  ...
})

其实功能很简单,就是通过传入的对象来判断是不是响应式对象和只读响应式对象。

编码

根据上一节,我们抽离的公共handler可以看到,我们在createGetter的时候其实已经做了区分,通过isReadonly参数就可以知道当前对象是什么类型,所以,接下来我们只需要触发对象的get操作,我们就可以知道当前对象的类型。

1、实现isReactive

// src/reactivity/reactive.ts
export const enum ReactiveFlags {
  IS_REACTIVE = "__v_isReactive"
}
...
export function isReactive (raw) {
  return !!raw[ReactiveFlags.IS_REACTIVE]  // !!是将undefined转换成boolean
}

这样,当我们执行isReactive(value)的时候就会调用value的get请求(value.__v_isReactive),接下来,我们在reactiveget请求里对他进行返回即可

// src/reactivity/baseHandlers.ts
import { ReactiveFlags } from "./reactive"
function createGetter (isReadonly = false) {
  return function get (target, key) {
    if (key === ReactiveFlags.IS_REACTIVE) {
      return !isReadonly
    }
    ...
  }
}

到此,isReactive就完成了,其实isReadonly原理一样,下面就一步步来实现isReadonly的逻辑

1、实现isReadonly

参考isReactive的实现思路,isReadonly同理。

// src/reactivity/reactive.ts
export const enum ReactiveFlags {
  ...,
  IS_READONLY = "__v_isReadonly"
}
...
export function isReadonly (raw) {
  return !!raw[ReactiveFlags.IS_READONLY]
}
// src/reactivity/baseHandlers.ts
function createGetter (isReadonly = false) {
  return function get (target, key) {
    if (key === ReactiveFlags.IS_REACTIVE) {
      ...
    } else if (key === ReactiveFlags.IS_READONLY) {
      return isReadonly
    }
    ...
  }
}

总结

通过调用对象的get方法,获取对象指定的属性,这里我们通过enum创建了一个枚举,方便统一管理属性名称,最后在createGetter中判断key的名称,进行返回。