实现readonly、isReactive、isReadonly

76 阅读1分钟

reanonly

readonly传入一个对象返回一个只读代理,实际上函数内部不需要进行依赖收集并且不允许修改。

function createGetter(readonly = false) {
  return function get(target, key) {
    const res = Reflect.get(target, key);
    //添加依赖
    if (!readonly) {
      track(target, key as string);
    }
    return res;
  };
}

function readonly(raw) {
  return new Proxy(raw, {
    get: createGetter(true),
    set: function (target, key: string, value) {
      console.warn(`目标对象${target}为readonly,key ${key} value ${value}`);
      return true;
    },
  });
}

isReactive

isReactive:检查一个对象是否是由 reactive 创建的响应式代理。

const enum ReactiveFlag {
  "IS_REACTIVE" = "is_reactive",
}

采用枚举能够清晰表达维护性更强

function isReactive(value) {
  if (!value || typeof value !== "object") {
    console.warn("value parameter exception");
    return false;
  }
  return !!value[ReactiveFlag.IS_REACTIVE];
}

通过访问该属性如果是一个普通对象那么肯定是undefined, 通过!! 进行转换成布尔值便是false

createGetter(readonly = false) {
  return function get(target, key) {
    const res = Reflect.get(target, key);
    if (key === ReactiveFlag.IS_REACTIVE) {
      return !readonly;
    }
    //添加依赖
    if (!readonly) {
      track(target, key as string);
    }
    return res;
  };
}

这是对reactiveget函数封装,当key等于is_reactive变量,代表用户访问该属性并且createGetter函数用户访问的key不是一个__v_isReactive,那么便进行依赖收集否则直接什么也不做。

isReadonly

isReadonly:检查一个对象是否是由 readonly 创建的只读代理

也是采用枚举方式配置变量

const enum ReactiveFlag {
  "IS_REACTIVE" = "is_reactive",
  "IS_READONLY" = "is_readonly",
}

下面和isReactive逻辑类似

function isReadonly(value) {
  if (!value || typeof value !== "object") {
    console.warn("value parameter exception");
    return false;
  }
  return !!value[ReactiveFlag.IS_READONLY];
}

function createGetter(readonly = false) {
  return function get(target, key) {
    const res = Reflect.get(target, key);
    if (key === ReactiveFlag.IS_REACTIVE) {
      return !readonly;
    }
    //新增
    if (key === ReactiveFlag.IS_READONLY) {
      return readonly;
    }
    //添加依赖
    if (!readonly) {
      track(target, key as string);
    }
    return res;
  };
}