【Vue3源码】第四章 实现isReadonly和isReactive

【Vue3源码】第四章 实现isReadonly和isReactive

前言

上一章节我们实现readonly API,并且优化之前写的reactive API。这一章我们实现isReadonly 和isReactive两个API。

1、实现isReactive

官网是这么介绍的:检查一个对象是否是由 reactive() 或 shallowReactive() 创建的代理。

原理很简单我们来实现一下这个函数~

先看单元测试代码

typescript 复制代码
import { reactive,isReactive } from "../reactive"


describe("reactive",() => {
    it("happy path",() => {
        const originObj = {foo:1}
        const observed = reactive(originObj)
        expect(observed).not.toBe(originObj)
        expect(observed.foo).toBe(1)
        //新增
        expect(isReactive(observed)).toBe(true)
        expect(isReactive(originObj)).toBe(false)
    })
})

实现isReactive

isReactive的原理很简单,我们怎么判断一个对象是否是由reactive()创建的呢?

还记得上一章节中我们在get捕获器中加入的isReadonly的参数吗?

是的这个参数就可以帮我们监测对象是reactive还是readonly,如果是reactive就调用track函数触发依赖

那么isReadonly参数也可以用来判断是否是个reactive()对象

所以我们可以在reactive.ts文件里新增如下代码:

typescript 复制代码
// 枚举
export const enum ReactiveFlags {
    IS_REACTIVE = "__v_isReactive",
}

// 传入对象后我们会去访问对象
export const isReactive = (value) => {
    return !!value[ReactiveFlags.IS_REACTIVE]
}

首先我们创建了一个枚举

枚举中我们设置一个用户基本不可能设置的key

那么我们就可以通过这个key,去访问对象中key对应的value

如果是个普通对象,访问value[ReactiveFlags.IS_REACTIVE] 自然是返回 undefined 所以直接用 !!undefined 转换成 false返回即可

那么如果是响应式对象呢?

如果是个响应式对象读取对象的值时,那么它就会先触发get捕获器

所以我们要到baseHandlers.ts文件下判断key是否是"__v_isReactive"即可

typescript 复制代码
import { track, trigger } from "./effect"
import { ReactiveFlags } from "./reactive"

function createGetter(isReadonly = false) {
  return function get(target, key) {
    //如果传入的key是ReactiveFlags.IS_REACTIVE
    if (key === ReactiveFlags.IS_REACTIVE) {
      //get捕获器就返回true告诉调用者这是一个reactive对象
      return !isReadonly
    } 

    const res = Reflect.get(target, key)
    if (!isReadonly) {
      track(target, key)
    }
    return res
  }
}

这就是isReactive函数在监测不同对象时的流程图:

2、实现isReadonly

其实是同理的直接上代码了

reactive.ts

typescript 复制代码
export const enum ReactiveFlags {
    IS_REACTIVE = "__v_isReactive",
    IS_READONLY = "__v_isReadonly"
}

export const isReactive = (value) => {
    return !!value[ReactiveFlags.IS_REACTIVE]
}

export const isReadonly = (value) => {
    return !!value[ReactiveFlags.IS_READONLY]
}

baseHandlers.ts

typescript 复制代码
import { ReactiveFlags } from "./reactive"

function createGetter(isReadonly = false) {
  return function get(target, key) {
    if (key === ReactiveFlags.IS_REACTIVE) {
      //get捕获器就返回true告诉调用者这是一个reactive对象
      return !isReadonly
    } else if (key === ReactiveFlags.IS_READONLY) {
      // 同理返回isReadonly证明是readonly
      return isReadonly
    }

    const res = Reflect.get(target, key)
    if (!isReadonly) {
      track(target, key)
    }
    return res
  }
}

流程图:

下节预告《vue3源码 优化stop功能》

相关推荐
“AI国潮设计-小江”21 分钟前
《Python+SDXL实战:用ControlNet精准控制“英歌舞翻糖吐司”构图,附批量生成脚本》
开发语言·人工智能·python·prompt·aigc
程序喵大人28 分钟前
【C++入门】编译链接模型 - 01 一个 C++ 程序是怎样变成可执行文件的
开发语言·c++·编译链接模型
陈随易44 分钟前
bm2,Node.js 与 Bun 项目部署新选择
前端·后端·程序员
可乐鸡翅yeah_2 小时前
FFmpeg 生成 HLS 独立分片 independent‑segments 参数到底有什么用
javascript·ffmpeg·音视频·safari·m3u8
sunshine22 girl2 小时前
Java学习七 Java 项目实战1-项目创建和主页面搭建
java·开发语言·学习
福兮说2 小时前
canvas 旋转图片的六个坑:四角被裁、Math.ceil 多出 1px 黑边、JPG 角发黑、翻转方向反了
前端·javascript·图像处理·canvas
菜鸟~noob2333 小时前
【电子战】第三季预告—波武器与电子系统强力毁伤
开发语言·数据库·matlab·电子战
Ai-_Man3 小时前
您您这可以把Grok的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。AI导出鸭
javascript·人工智能·ai·小程序·电脑
惊讶的猫3 小时前
工具选对之后还不够:商城 Agent 的参数与权限治理
开发语言·python
传人once4 小时前
多图片上传预览功能如何写
前端·css·html·jquery·html5