一起学Vue3源码,实现最简Vue3【06】 - 实现 readonly 功能

实现 readonly 功能

什么是readonly?
顾名思义 – 就是只能读,不能修改。
TDD编码思维,测试 -> 实现 -> 重构代码 -> 优化

readonly.spec.ts

describe("readonly", () => {
  it("happy path", () => {
    // set not be triggered
    const original = { prop: 1, bar: { age: 10 } };
    const wrapped = readonly(original);
    expect(wrapped).not.toBe(original);
    expect(wrapped.prop).toBe(1);
  });

  it("warning when set triggered", () => {
    // mock   console.warn 警告函数调用
    console.warn = jest.fn();

    const user = readonly({
      age: 10,
    });

    user.age = 11;

    expect(console.warn).toBeCalled();
  });
});

首先来实现第一个测试功能,readonly

reactive.ts

// 封装成通用创建 Proxy 函数
function createActiveObj(raw: any, baseHandlers) {
  return new Proxy(raw, baseHandlers);
}

export function readonly(raw) {
  return createActiveObj(raw, readonlyHandlers);
}

1、首先,由于都是响应对象,把readonly和reactive 抽离出公共逻辑去使用,这里就是代码重构思想,(由于图文形式,直接放重构后的代码,会一一讲解)
2、createActiveObj 就是创建个代理对象,接收两个参数,一个代理对象,一个处理代理对象的方法
readonlyHandlers 本质就是一个对象格式,所以我们直接抽离到公共文件baseHandlers内

baseHandlers.ts

import { extend, isObject } from "../../shared";
import { track, trigger } from "./effect";
import { reactive, readonly } from "./reactive";

// 缓存一下get, set 后面始终用同一个
const get = createGetter();
const set = createSetter();
const readonlyGet = createGetter(true);

// 创建 get 通用方法
function createGetter(isReadonly: Boolean = false) {
  return function get(target, key) {
    const res = Reflect.get(target, key);

    if (!isReadonly) {
      // 收集依赖
      track(target, key);
    }
    return res;
  };
}

// 创建 set 通用方法
function createSetter() {
  return function set(target, key, value) {
    const res = Reflect.set(target, key, value);

    // 触发依赖
    trigger(target, key);
    return res;
  };
}

// 导出 reactive 代理
export const mutableHandlers = {
  get,
  set,
};

// 导出 readonly 代理
export const readonlyHandlers = {
  get: readonlyGet,
  set(target, key, value) {
    // 警告函数
    console.warn(
      `${String(key)} cannot be set, because target is readonly, ${target}`
    );
    return true;
  },
};

readonlyHandlers 就是 readonly 代理,由于readonly是只读,所以就不存在依赖收集和依赖触发,所以创建 get 通用方法 createGetter 中 isReadonly 属性来去做校验,是readonly就不用依赖收集;
而后,触发set的时候返回一个警告函数,就是上面第二个测试。
// mock console.warn 警告函数调用 console.warn = jest.fn();

最后,执行 yarn test

总结

本章节相对简单,就是一个弱化的reactive,主要是代码重构方面,抽离出reactive和readonly 通用逻辑。
最后,附上git代码:mini-vue

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值