深入解析 Vue 3 源码:computed 的底层实现原理

作者:excel日期:2025/10/9

在 Vue 3 的响应式系统中,computed 是一个非常重要的功能,它用于创建基于依赖自动更新的计算属性。本文将通过分析源码,理解 computed 的底层实现逻辑,帮助你从源码层面掌握它的原理。


一、computed 的基本使用

在使用层面上,computed 有两种常见用法:

1. 只读计算属性

1const count = ref(1)
2const plusOne = computed(() => count.value + 1)
3
4console.log(plusOne.value) // 输出 2
5plusOne.value++ // 报错,因只读
6

2. 可写计算属性

1const count = ref(1)
2const plusOne = computed({
3  get: () => count.value + 1,
4  set: (val) => { count.value = val - 1 }
5})
6
7plusOne.value = 3
8console.log(count.value) // 输出 2
9

这两种形式在底层源码中都会通过一个统一的类 ComputedRefImpl 来实现。


二、核心类:ComputedRefImpl

ComputedRefImpl 是 Vue 3 中计算属性的核心实现类,它实现了响应式依赖追踪和懒执行机制。

1. 成员属性解析

1export class ComputedRefImpl<T = any> implements Subscriber {
2  _value: any = undefined          // 缓存计算后的值
3  dep: Dep = new Dep(this)         // 依赖收集容器
4  readonly __v_isRef = true        // 标记为 ref 类型
5  readonly __v_isReadonly: boolean // 是否只读
6  deps?: Link                      // 依赖链表(订阅者)
7  flags: EffectFlags = EffectFlags.DIRTY // 标志位,初始为脏值
8  globalVersion: number = globalVersion - 1 // 全局版本号
9  isSSR: boolean                   // 是否在服务端渲染环境中
10  next?: Subscriber = undefined    // 下一个订阅者
11
12  // 调试钩子
13  onTrack?: (event: DebuggerEvent) => void
14  onTrigger?: (event: DebuggerEvent) => void
15
16  constructor(
17    public fn: ComputedGetter<T>,
18    private readonly setter: ComputedSetter<T> | undefined,
19    isSSR: boolean,
20  ) {
21    this[ReactiveFlags.IS_READONLY] = !setter
22    this.isSSR = isSSR
23  }
24}
25

关键点:

  • flags:使用 EffectFlags 管理状态,如 DIRTY 表示需要重新计算。
  • dep:内部维护依赖列表,供其他响应式对象追踪。
  • _value:缓存上次计算的值,实现懒计算。
  • __v_isReadonly:若没有传入 setter,则为只读计算属性。

三、value 的访问逻辑

1get value(): T {
2  const link = this.dep.track() // 依赖追踪
3  refreshComputed(this)         // 若脏则重新计算
4  if (link) {
5    link.version = this.dep.version
6  }
7  return this._value
8}
9

这里是 computed 的核心机制:

  1. 依赖追踪:通过 dep.track() 让当前计算属性被其他响应式数据订阅。
  2. 惰性求值:只有在访问 .value 时,才会执行 getter 重新计算。
  3. 版本同步link.version 确保依赖的版本号一致,以判断是否需要重新计算。

四、value 的设置逻辑

1set value(newValue) {
2  if (this.setter) {
3    this.setter(newValue)
4  } else if (__DEV__) {
5    warn('Write operation failed: computed value is readonly')
6  }
7}
8
  • 若定义了 setter,则允许外部修改计算属性值;
  • 否则在开发环境中发出警告,提示为只读属性。

五、依赖更新与通知机制

当依赖的响应式数据发生变化时,notify() 会被调用:

1notify(): true | void {
2  this.flags |= EffectFlags.DIRTY // 标记为脏值
3  if (!(this.flags & EffectFlags.NOTIFIED) && activeSub !== this) {
4    batch(this, true) // 批量更新依赖
5    return true
6  }
7}
8

这里的关键是:

  • 标记为 “脏”,下次访问时会重新计算;
  • 通过 batch 批量更新,避免重复通知。

六、computed 函数入口

外层的 computed 函数是一个工厂方法:

1export function computed<T>(
2  getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
3  debugOptions?: DebuggerOptions,
4  isSSR = false,
5) {
6  let getter: ComputedGetter<T>
7  let setter: ComputedSetter<T> | undefined
8
9  if (isFunction(getterOrOptions)) {
10    getter = getterOrOptions
11  } else {
12    getter = getterOrOptions.get
13    setter = getterOrOptions.set
14  }
15
16  const cRef = new ComputedRefImpl(getter, setter, isSSR)
17
18  if (__DEV__ && debugOptions && !isSSR) {
19    cRef.onTrack = debugOptions.onTrack
20    cRef.onTrigger = debugOptions.onTrigger
21  }
22
23  return cRef as any
24}
25

这里做了两件事:

  1. 根据参数判断是只读还是可写计算属性;
  2. 创建 ComputedRefImpl 实例;
  3. 如果处于开发模式,还会绑定调试钩子(onTrackonTrigger)。

七、总结

Vue 3 中的 computed 实现基于以下关键机制:

机制作用
惰性求值 (Lazy Evaluation)仅在访问时计算结果
缓存结果 (Caching)若依赖未变则返回缓存值
依赖追踪 (Dependency Tracking)自动感知依赖变化
脏标记 (Dirty Flag)控制何时重新计算
批量更新 (Batching)提高性能,减少重复通知

从源码可以看到,computed 实际上是一个特殊的 ref,但拥有更多的依赖追踪与缓存机制,是 Vue 响应式系统中非常精妙的一环。


本文内容由人工智能生成,仅供学习与参考使用,请在实际应用中结合自身情况进行判断。


深入解析 Vue 3 源码:computed 的底层实现原理》 是转载文章,点击查看原文


相关推荐


CICD工具选型指南,Jenkins vs Arbess哪一款更好用?
高效研发之旅2025/10/8

Jenkins是一款常用的CICD工具,Arbess作为一款新兴的国产开源免费的CICD工具,两款工具各有特点。本文将从安装配置、功能特性、用户体验等几个方面对两款软件进行详细对比。 1、安装配置 项目 Jenkins Arbess 安装难度需要预装Java环境,需要手动配置端口和后台服务。一键安装,私有部署不同环境均支持傻瓜式一键安装。配置难度需要配置国内镜像源,安装核心插件零配置,安装后即刻可用,无需额外配置。支持操作系统支持Windows、ma


【征文计划】基于Rokid CXR-M SDK 打造AI 实时会议助手:从连接到自定义界面的完整实践
_摘星_2025/10/6

【征文计划】基于Rokid CXR-M SDK 打造AI 实时会议助手:从连接到自定义界面的完整实践 > **摘要**:本文基于 Rokid CXR-M SDK,详细阐述如何构建一个面向商务会议场景的“AI 实时会议助手”应用。通过手机端与 Rokid 智能眼镜的协同,实现语音转写、要点提炼、提词引导、多语翻译与会后纪要自动生成。文章涵盖从环境配置、蓝牙/Wi-Fi 连接、设备控制、AI 场景交互到自定义 UI 渲染的完整开发流程,并提供关键代码示例与最佳实践建议。 > > ![](https:


第4篇 vs2019+QT调用SDK连接海康相机显示图片
txwtech笛克电科2025/10/5

vs2019+QT调用SDK连接海康相机显示图片 连接,采图,获取与设置参数,曝光,增益,帧率 新建项目-文件结构: debug x64 调用类: TTcamera.cpp #include "TTcamera.h" #include <QDebug> TTcamera::TTcamera() { m_hDevHandle = NULL; m_pBufForSaveImage = nullptr; m_nBufSizeForSaveImage = 0;


AI 自动化测试:接口测试全流程自动化的实现方法
Jinkxs2025/10/4

在 AI 技术飞速渗透各行各业的当下,我们早已告别 “谈 AI 色变” 的观望阶段,迈入 “用 AI 提效” 的实战时代 💡。无论是代码编写时的智能辅助 💻、数据处理中的自动化流程 📊,还是行业场景里的精准解决方案 ,AI 正以润物细无声的方式,重构着我们的工作逻辑与行业生态 🌱。曾几何时,我们需要花费数小时查阅文档 📚、反复调试代码 ⚙️,或是在海量数据中手动筛选关键信息 ,而如今,一个智能工具 🧰、一次模型调用 ⚡,就能将这些繁琐工作的效率提升数倍 📈。正是在这样的变革中,AI


基于PyTorch的CIFAR10加载与TensorBoard可视化实践
StarPrayers.2025/10/3

视频学习来源:https://www.bilibili.com/video/BV1hE411t7RN?t=1.1&p=15 import torchvision from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriter from test_03 import writer # 添加 添加 download=True 参数来下载数据集 test_data = torchv


什么是 ONNX Runtime?
Cosolar2025/10/2

在人工智能技术飞速发展的今天,模型训练与部署之间的“鸿沟”始终是行业痛点——训练好的模型往往因框架差异、硬件限制等问题难以高效落地。而ONNX Runtime的出现,为这一难题提供了强有力的解决方案。作为微软开源的跨平台推理引擎,ONNX Runtime凭借其跨框架兼容性、全硬件加速能力和极致的性能优化,已成为AI模型部署领域的关键基础设施。本文将深入解析ONNX Runtime的核心价值、技术原理与应用场景,带你领略它如何为AI落地“加速”。 1、什么是ONNX Runtime? ONNX R


关于win11的Microsoft To Pdf打印机修改端口后无法再刷新显示于设备界面的问题
随风万里无云2025/10/2

请记住,有时候死钻牛角尖,反倒是不值得; 从24号到30号,再到今天国庆节第一天才记录,这就是过程,每个过程都结束的时候, 所以,请别焦虑,或许换个思路,就能柳暗花明又一村 (如果你只是需要解决的方法,直接看2.2往后) 1.问题起因: 我需要修改端口实现打印不弹出选择的保存界面,直接存在固定的位置 2.修改完成端口本地端口为固定路径 测试打印没问题,然后离谱的就出现了! 设备界面中再也找不到这个打印机了,但是你打印的时候依旧可以正常打印 我在网上找了很多帖子想要


分布式秒杀系统设计方案
nlog3n10/2/2025

核心组件说明1. 接入层CDN: 静态资源缓存,减少服务器压力Nginx: 负载均衡,请求分发,限流API Gateway: 统一入口,认证,限流,熔断2. 应用层秒杀服务: 核心业务逻辑处理用户服务: 用户认证和信息管理商品服务: 商品信息管理订单服务: 订单处理和管理支付服务: 支付处理3. 中间件层Redis集群: 缓存热点数据,分布式锁RocketMQ: 异步消息处理,削峰填谷Elasticsearch: 日志分析和搜索4. 数据层MySQL主从集群:


2025 年 AI+BI 趋势下,Wyn 商业智能软件如何重构企业决策效率?
葡萄城技术团队9/30/2025

2025年AI+BI趋势下,Wyn商业智能软件通过&quot;嵌入式架构+AI原生能力&quot;重构企业决策效率。Gartner预测,60%的企业将依赖自然语言交互完成数据分析。Wyn具备三大核心优势:1)零门槛AI对话分析,业务人员可自然语言提问获取分析结果;2)国产化与灵活部署,适配统信UOS等国产系统;3)嵌入式全域集成,可融入MES、OA等业务系统。典型案例显示,Wyn帮助制造企业减少40%设备停机时间,医药企业提升70%决策响应速度。选型考量聚焦可信性、易用性、集成性和国产化。


先用js快速开发,后续引入ts是否是一个好的实践?
你的人类朋友2025/10/11

前言 我在业余时间做一些小项目时,每次进行技术选型,都会有一个疑问: 应该直接使用 TypeScript 开发,还是先用 JavaScript 快速启动,后续再引入 TypeScript? 今天干脆来整理一下思路,方便后续复用这些想法 正文 一、快速开发的优势 先用 JavaScript 进行快速开发确实有其明显优势: 开发速度更快 无需类型定义和接口声明 跳过类型检查的编译步骤 ⭐ 【重要】特别适合【原型开发】和【概念验证】,个人认为这个是最重要的 学习成本低 更容易上手 ⭐ 【重要】减

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0