11.实现isReactive和isReadonly

207 阅读1分钟

一、编写单元测试

isReactive单元测试编写

import {reactive,isReactive} 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)
  })
})

isReadonly单元测试编写

import { readonly,isReadonly} from '../reactive'
describe("readonly", () => {
  it("happy path", () => {
    // not set
    const original = {foo: 1,bar: {baz: 2}};
    const wrapped = readonly(original);
    expect(wrapped).not.toBe(original);
    expect(isReadonly(wrapped)).toBe(true);
    expect(wrapped.foo).toBe(1)
  })

  it('warn then call set', () => {
    const user = readonly({
      age: 10
    })
    console.warn = jest.fn();
    user.age = 11;
    expect(console.warn).toBeCalled();
  })
})

二、功能实现

由于响应式对象会通过reactive进行get和set的代理,在get方法内部预先约定好获取约定键值,对于响应式对象会增加该键值,所以可以通过该键值判断该值是否是响应式对象或只读对象。

reactive.ts

export const enum ReactiveFlags {
  IS_REACTIVE = "_v_isReactive",
  IS_READONLY = "_v_isReadonly"
}

export function isReactive (value) {
  return !!value[ReactiveFlags.IS_REACTIVE];
}

export function isReadonly (value) {
  return !!value[ReactiveFlags.IS_READONLY]
}

baseHandlers.ts

function createGetter(isReadonly = false){
  return function get(target,key){
    if(key === ReactiveFlags.IS_REACTIVE){
      return !isReadonly;
    } else if (key === ReactiveFlags.IS_READONLY){
      return isReadonly;
    }
    const res = Reflect.get(target,key);
    if(!isReadonly){
      track(target,key)
    }
    return res;
  }
}

三、单元测试

完成后,我们可以通过yarn test --watchAll执行所有的测试。

yarn test --watchAll