10.实现readonly功能

169 阅读1分钟

一、单元测试编写

创建readonly.spec.ts文件,编写测试代码。readonly创建的数据可以被读取,但是不可以被set.

import { readonly} 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(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();
  })
})

二、代码功能实现

export function readonly(raw){
  return new Proxy(raw, {
    get(target,key){
      const res = Reflect.get(target,key);
      return res;
    },
    set(target,key,value){
    //此处可以抛出一个warn
      console.warn('key:${key} set 失败,因为 target 是 readonly',target)
      return true;
    }
  })
}

三、执行测试

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

yarn test --watchAll

四、代码重构

完成功能后,我们可以对代码进行优化重构。

baseHandlers.ts

import {track, trigger} from "./effect";

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(!isReadonly){
      track(target,key)
    }
    return res;
  }
}
function createSetter (){
  return function (target, key, value) {
    const res = Reflect.set(target, key, value);
    trigger(target, key);
    return res;
  }
}
export const mutableHandler = {
  get,
  set
}

export const readonlyHandlers = {
  get:readonlyGet,
  set(target,key,value){
    console.warn('key:${key} set 失败,因为 target 是 readonly',target)
    return true;
  }
}

reactive.ts

import { mutableHandler, readonlyHandlers } from './baseHandlers';

export function reactive(raw){
  return createActiveObject(raw,mutableHandler)
}

export function readonly(raw){
  return createActiveObject(raw,readonlyHandlers);
}
function createActiveObject(raw: any, baseHandlers){
  return new Proxy(raw,baseHandlers);
}