【Vue3 源码解析】computed

news2024/12/23 13:37:15
export function computed<T>(
  getter: ComputedGetter<T>,
  debugOptions?: DebuggerOptions
): ComputedRef<T>
export function computed<T>(
  options: WritableComputedOptions<T>,
  debugOptions?: DebuggerOptions
): WritableComputedRef<T>
export function computed<T>(
  getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
  debugOptions?: DebuggerOptions,
  isSSR = false
) {
  // 格式化参数
  let getter: ComputedGetter<T>
  let setter: ComputedSetter<T>

  // 如果传过来的是一个函数(即函数式写法),那么就是只读的
  const onlyGetter = isFunction(getterOrOptions)
  if (onlyGetter) {
    getter = getterOrOptions  // 我们传过来的函数赋值给 getter
    setter = __DEV__  // 不支持 setter, 否则会报错
      ? () => {
          console.warn('Write operation failed: computed value is readonly')
        }
      : NOOP
  } else {  // 选项式写法 可读可写
    getter = getterOrOptions.get  
    setter = getterOrOptions.set
  }

  // 将 getter 和 setter 传入这个类
  const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR)

  if (__DEV__ && debugOptions && !isSSR) {
    cRef.effect.onTrack = debugOptions.onTrack
    cRef.effect.onTrigger = debugOptions.onTrigger
  }

  return cRef as any
}

这段代码是 computed 函数内部的逻辑,用于根据传入的参数 getterOrOptions 创建计算属性的 gettersetter,然后创建一个 ComputedRefImpl 实例并返回。

以下是代码的详细解释:

  1. 首先,定义了 gettersetter 变量,用于后续存储计算属性的获取和设置函数。

  2. 通过检查 getterOrOptions 是否为函数来判断是函数式写法还是选项式写法。函数式写法表示计算属性是只读的,因此 getterOrOptions 直接赋值给 getter 变量,而 setter 变量则被设置为一个函数。这个函数用于在开发环境下报错,提示用户不能对只读的计算属性进行写入操作。

    // 只读的计算属性,直接使用传入的 getter 函数
    if (onlyGetter) {
      getter = getterOrOptions;  // 传入的函数作为 getter
      setter = __DEV__  // 如果是开发环境,设置 setter 为一个警告函数
        ? () => {
            console.warn('Write operation failed: computed value is readonly')
          }
        : NOOP;  // 否则设置为空函数 NOOP
    }
    
  3. 如果不是函数式写法,表示计算属性是可读可写的。此时,从传入的 getterOrOptions 对象中提取 getset 函数,分别赋值给 gettersetter 变量。

    } else {  // 选项式写法,可以读写
      getter = getterOrOptions.get;  // 从选项对象中提取 getter
      setter = getterOrOptions.set;  // 从选项对象中提取 setter
    }
    
  4. 创建 ComputedRefImpl 实例 cRef,将 gettersetter、只读标志以及 isSSR 参数传入。cRef 代表了最终的计算属性对象。

    // 创建 ComputedRefImpl 实例
    const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);
    
  5. 在开发环境下,如果传入了调试选项 debugOptions 并且不是服务端渲染(isSSRfalse),则将调试选项中的 onTrackonTrigger 回调函数分别赋值给 cRef.effect.onTrackcRef.effect.onTrigger,用于跟踪计算属性的依赖和触发情况。

    if (__DEV__ && debugOptions && !isSSR) {
      cRef.effect.onTrack = debugOptions.onTrack;
      cRef.effect.onTrigger = debugOptions.onTrigger;
    }
    
  6. 最后,将创建的 cRef 对象返回,它包含了计算属性的值、获取和设置函数等信息。

    return cRef as any;
    

总之,这段代码是 computed 函数内部的逻辑,用于根据传入的参数创建计算属性的 gettersetter 函数,并最终创建一个 ComputedRefImpl 实例,返回计算属性对象。根据不同的写法和配置,可以创建只读或可读可写的计算属性。

然后我们具体看一下 ComputedRefImpl 实例:

export class ComputedRefImpl<T> {
  public dep?: Dep = undefined

  private _value!: T
  public readonly effect: ReactiveEffect<T>

  public readonly __v_isRef = true
  public readonly [ReactiveFlags.IS_READONLY]: boolean = false

  public _dirty = true  // 看是否是脏的,是否需要重新计算
  public _cacheable: boolean

  constructor(
    getter: ComputedGetter<T>,
    private readonly _setter: ComputedSetter<T>,
    isReadonly: boolean,
    isSSR: boolean
  ) {
    // 创建 ReactiveEffect 对象,用于管理计算属性的响应式依赖
    // 依赖变化并且脏值为 false ,依赖变化这个函数才会执行
    this.effect = new ReactiveEffect(getter, () => {
      if (!this._dirty) {
        this._dirty = true
        triggerRefValue(this)
      }
    })

    // 将计算属性与 ReactiveEffect 对象关联
    this.effect.computed = this
    this.effect.active = this._cacheable = !isSSR // 根据是否在服务器端渲染设置是否缓存计算结果
    this[ReactiveFlags.IS_READONLY] = isReadonly // 标记是否为只读计算属性
  }

  // 收到脏值为 true ,直接执行 get value 函数
  get value() {
    // 计算属性的获取方法,用于获取计算属性的值
    const self = toRaw(this) // 获取原始的计算属性对象,脱离 Proxy 代理
    trackRefValue(self) // 跟踪计算属性的引用
    if (self._dirty || !self._cacheable) {
      // 如果属性标记为脏(需要重新计算)或者不可缓存,则重新计算属性值
      self._dirty = false
      self._value = self.effect.run()! // 运行计算属性的 effect 函数以计算新值
    }
    return self._value
  }

  set value(newValue: T) {
    // 计算属性的设置方法,用于设置计算属性的值
    this._setter(newValue) // 调用用户提供的 setter 函数
  }
}

这段代码定义了 ComputedRefImpl 类,该类是 Vue 3 中计算属性(computed)的实现的一部分。

在这里插入图片描述

对代码的主要解释如下:

  1. ComputedRefImpl 类用于实现计算属性。它接受以下参数:

    • getter: 计算属性的获取函数,用于计算属性的值。
    • _setter: 计算属性的设置函数,用于设置计算属性的值。
    • isReadonly: 一个布尔值,表示计算属性是否只读。
    • isSSR: 一个布尔值,表示是否在服务器端渲染。
  2. 在构造函数中,创建了一个 ReactiveEffect 对象,该对象将 getter 函数传递给它,并定义了一个回调函数。当计算属性的依赖发生变化时,这个回调函数将被触发。回调函数会将 _dirty 属性设置为 true,表示计算属性需要重新计算,并调用 triggerRefValue(this),通知相关依赖进行更新。

  3. 将创建的 ReactiveEffect 对象与当前的 ComputedRefImpl 实例关联,以便后续进行管理和跟踪。

  4. 根据传入的参数,设置 effectactive 属性和 _cacheable 属性。active 表示是否需要在计算属性失活时停止计算,_cacheable 表示是否可以缓存计算结果。

  5. 定义 get value() 方法,用于获取计算属性的值。在获取属性值之前,会调用 trackRefValue(self) 来跟踪计算属性的引用。如果计算属性被标记为脏(需要重新计算)或者不可缓存,将重新计算属性值,并将 _dirty 设置为 false,以表示属性值已经计算完毕。

  6. 定义 set value(newValue: T) 方法,用于设置计算属性的值。它会调用用户提供的 _setter 函数来进行属性值的设置。

总之,这段代码实现了计算属性的核心逻辑,包括属性值的获取和设置,以及属性值的计算和缓存管理。计算属性可以根据其依赖自动更新,并且可以选择是否设置为只读。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1043725.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SPA项目之主页面--动态树右侧内容管理

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于VueElementUI的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.左侧动态树 1.定义组件 ①样式…

【神印王座】悲啸洞穴之物揭晓,圣采儿差点被骗,幸好龙皓晨聪明

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析神印王座。 神印王座动漫现阶段已经出到龙皓晨等人接取新任务深入魔族地界的阶段&#xff0c;而龙皓晨等人接取的任务想必现在大家都知道了&#xff0c;那就是探索魔族地界中的悲啸洞穴。但是大家知道悲啸洞穴里面藏着什么…

智能的障碍:符号化

基于事实与价值叠加的算计与基于事实的计算有着明显的区别。 基于事实的计算是指根据已有的客观事实和数据进行计算和推理。在这种计算中&#xff0c;只考虑和利用与事实相关的信息和数据&#xff0c;目的是得出合理的、基于客观事实的结论。例如&#xff0c;使用数学公式和逻辑…

python实现全局变量共享,一个全局变量在多个文件中使用

因为业务需求要将抓到的数据进行累加统计&#xff0c;而且还要间隔三秒钟将这个数据推送到服务端&#xff0c;所以就要实现一个全局变量来记录这个数据&#xff0c;而且推送服务要每隔三秒钟就推送一次到服务端。之前使用了一个全局文件common.py&#xff0c;里面存储这个变量t…

【CV学习笔记】tensorrtx-yolov5 逐行代码解析

1、前言 TensorRTx(下文简称为trtx)是一个十分流行的利用API来搭建网络结构实现trt加速的开源库&#xff0c;作者提到为什么不用ONNX parser的方式来进行trt加速&#xff0c;而用最底层的API来搭建trt加速的方式有如下原因: Flexible 很容易修改模型的任意一层&#xff0c;删…

渗透测试——信息收集思路

文章目录 信息收集域名与 IPOSINTCDNCDN的作用如何检测是否存在CDN CDN 绕过多地Ping邮件服务器子域名真实IP寻找国外地址请求查找老域名查找关联域名信息泄露/配置文件网站漏洞DNS记录&#xff0c;证书域名历史 搜索引擎语法WHOIS端口对外开放情况Nmap 网站的三种部署模式网站…

chrome extensions mv3通过content scripts注入/获取原网站的window数据

开发插件的都知道插件的content scripts和top window只共享Dom不共享window和其他数据&#xff0c;如果想拿挂载在window的数据还有点难度&#xff0c;下面会通过事件的方式传递cs和top window之间的数据写一个例子 代码 manifest.json 这里只搞了2个js&#xff0c;content.…

DataX - 在有总bps限速条件下,单个channel的bps值不能为空,也不能为非正数

更新服务器上的datax版本后&#xff0c;发现执行以前的任务全都失败&#xff0c;查看日志都有报 com.alibaba.datax.common.exception.DataXException: Code:[Framework-03], Description:[DataX引擎配置错误&#xff0c;该问题通常是由于DataX安装错误引起&#xff0c;请联系…

ssl证书 阿里的域名,腾讯云的证书

目录 1.腾讯云申请ssl免费证书 2.去阿里云进行解析 3.回到腾讯云 4.nginx的配置 说明&#xff1a;阿里云的免费证书用完了&#xff08;每年可以申请20个&#xff09;&#xff0c;还有个项目要用证书&#xff0c;第三方的证书免费的都是90天的。看了下腾讯云业可以申请免费的…

史上最全的公司各种体系流程图,直接拿走!

大家好&#xff0c;我是老原。 优秀企业和卓越企业的区别在哪里&#xff1f; 两个字&#xff1a;流程。 流程的水平高低在一定程度上也体现了项目经理做项目的能力&#xff0c;一个企业能否持续成功的过程能力。 拥有稳定高效的流程管理体系&#xff0c;项目经理的管理水平…

ABB机器人如何在示教器上查看输入输出以及强制输出DO信号

ABB机器人如何在示教器上查看输入输出以及强制输出DO信号 如下图所示,点击左上角的菜单—选择“输入输出“, 如下图所示,进入输入输出画面后,点击右下角的视图,选择“数字输出“, 如下图所示,此时可以看到所有的DO信号及其当前值, 如下图所示,这里以 Local_IO_0_DO1 为…

AI大模型服务上线,助力企业AI大模型应用落地

在数字时代的浪潮中&#xff0c;人工智能(AI)技术的发展和应用已经深入到我们生活的方方面面。其中&#xff0c;企业AI大模型作为AI技术的重要形式之一&#xff0c;正在成为推动企业创新、提高效率和优化决策的关键力量。为顺应AI大模型的新趋势需求&#xff0c;近日&#xff0…

游戏技术亮点|Aavegotchi 与 GameSwift 建立合作伙伴关系

构建一个优秀的游戏只是成功发布的一部分&#xff0c;让数百万玩家体验这款游戏才是真正的乐趣所在。 这也是为什么我们很高兴宣布与 GameSwift 建立了新的合作伙伴关系&#xff0c;GameSwift 是一款先进的模块化游戏区块链&#xff0c;采用 zkEVM 技术构建&#xff0c;是全球…

【通意千问】大模型GitHub开源工程学习笔记(1)

9月25日&#xff0c;阿里云开源通义千问140亿参数模型Qwen-14B及其对话模型Qwen-14B-Chat,免费可商用。 立马就到了GitHub去fork。 GitHub&#xff1a; GitHub - QwenLM/Qwen: The official repo of Qwen (通义千问) chat & pretrained large language model proposed b…

解决谷歌Redux DevTools调试React+Typescript项目数据对不上/连接不上问题

上文 ReactTypescript项目环境中搭建并使用redux环境 我们创建了一个redux项目的环境 但是我们用谷歌浏览器插件调试 会发现 要不 匹配的数据有问题 看不到数据 要不 就压根连接不到 而且 我们点击加减号 去改变值 调试工具也没有任何反应 我们终端输入 npm install --save-d…

VSCode安装离线插件

1. 打开 VSCode 插件市场网址 Extensions for the Visual Studio family of product&#xff0c;输入你想要的插件名称&#xff0c;比如这里我想要安装的是 Markdown All in One 插件 2. 点击进入插件主页&#xff0c;点击右侧的 Download Extension 链接&#xff0c;得到下载…

Hugging News #0925: 一览近期的新功能发布

每一周&#xff0c;我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新&#xff0c;包括我们的产品和平台更新、社区活动、学习资源和内容更新、开源库和模型更新等&#xff0c;我们将其称之为「Hugging News」。本期 Hugging News 有哪些有趣的消息&#xff0…

通讯网关软件013——利用CommGate X2ORACLE实现Modbus RTU数据转储ORACLE

本文介绍利用CommGate X2ORACLE实现从Modbus RTU设备读取数据并转储至ORACLE数据库。CommGate X2ORACLE是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;实现从Modbus RTU设备读取数据并转储至ORACL…

【漏洞复现】某友GRP-U8 SQL注入

漏洞描述 某友GRP-U8是某友软件推出的企业级管理软件套件,旨在助力企业实现全面数字化管理及业务优化,某友GRP-U8的bx_historyDataCheck.jsp接口对用户传入的参数未进行有效的过滤,直接拼接至SQL查询的语句中,导致SQL注入漏洞,攻击者可利用该漏洞获取数据库的敏感信息 …

springboot实战(八)之整合redis

目录 序言&#xff1a; 环境&#xff1a; 依赖&#xff1a; 配置&#xff1a; 测试&#xff1a; redis序列化配置&#xff1a; 连接池&#xff1a; 序言&#xff1a; Redis是我们Java开发中&#xff0c;使用频次非常高的一个nosql数据库&#xff0c;数据以key-value键…