vue:响应式原理解析,深入理解vue的响应式系统

一、文章秒读

vue的响应式系统核心有两个,简单描述就是:

1.在数据变化时重新render依赖相关函数(组件)。

2.在vue2和vue3中分别使用Object.defineProperty和Proxy进行对象属性的读写。

数据变化时:

二、什么是响应式

当依赖数据发生改变时,与之关联的数据或计算结果能够自动更新就是响应式。

我们用代码可以更直观理解:

let A0=1;
let A1=2;
let A2;
function update() {A2 = A0 + A1
}
whenDepsChange(update);

在代码中

首先,我们定义了一个update()函数来作为我们需要在数据变化时进行的操作。这个操作会更改程序的某个状态,也就是说这是个副作用函数,简称为作用 (effect)。

其次,我们还需要定义一个whenDepsChange()函数,让它能够在数据变化时执行update()函数。

这个 whenDepsChange() 函数有如下的任务:

  1. 当一个变量被读取时进行追踪。例如我们执行了表达式 A0+A1 的计算,则 A0 和 A1 都被读取到了。在这里,A0 和 A1 被视为这个作用的依赖 (dependency),因为它们的值被用来执行前面提到的作用。这次作用也可以被称作它的依赖的一个订阅者 (subscriber)

  2. 如果一个变量在当前运行的副作用中被读取了,就将该副作用设为此变量的一个订阅者。例如由于 A0 和 A1 在 update() 执行时被访问到了,则 update() 需要在第一次调用之后成为 A0 和 A1 的订阅者。

  3. 探测一个变量的变化。例如当我们给 A0 赋了一个新的值后,应该通知其所有订阅了的副作用重新执行。

综上所述,我们可以简单的将响应式过程理解为:

依赖数据变化=>触发对该变量追踪的函数(监听变化)=>触发副作用函数(触发更新)

三、Vue是如何实现响应式的

1.数据的get和set

在标准的JavaScript中,直接追踪局部变量(如函数内的变量)的读写操作是不可能的,因为语言本身没有提供这样的机制。但是,对于对象的属性,JavaScript提供了可以利用的特性来间接实现这种追踪。

1. Object.defineProperty
Object.defineProperty允许你定义或修改对象上的一个属性,并且可以指定该属性的访问器方法(getter和setter)。当属性被读取或设置时,相应的getter或setter将被调用。

示例:

    <script>const obj = {};// 定义属性'value',包含getter和setterObject.defineProperty(obj, "value", {get() {console.log("get value");return this._value;},set(newValue) {console.log("set value");this._value = newValue;},// 可以通过这个属性来控制属性的可枚举性configurable: true,// 可以通过这个属性来控制属性的可写性enumerable: true,});obj.value = 5;console.log(obj.value); // get value ,set value, 5</script>

2.Proxy
Proxy对象允许你拦截并自定义对象的基本操作,包括属性访问和修改。这使得你可以创建一个代理对象,当访问或修改目标对象的属性时,会触发预定义的行为。

示例:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>基础 ref()</title></head><body><button id="updateButton">点击+1</button><div id="message"></div><script>const createRef = (initialValue) => {return new Proxy({ value: initialValue },{get(target, key) {return target[key];},set(target, key, value) {target[key] = value;if (key === "value") {updateDisplay(); // 当.value被设置时,更新DOM}return true;},});};// 初始化refconst numberRef = createRef(0);// 更新DOM的函数const updateDisplay = () => {document.getElementById("message").innerText = numberRef.value;};// 绑定按钮点击事件document.getElementById("updateButton").addEventListener("click", () => {numberRef.value++; // 点击按钮时计数器加一});// 初始显示updateDisplay();</script></body>
</html>

在vue2中,出于支持旧版本浏览器的限制,使用了Object.defineProperty

在vue3中,则使用了功能更为强大的Proxy

2.vue实现响应式的过程

下文中讲到的视图更新:在vue中,模板会编译为渲染函数,也就是我们响应式中的副作用函数。当数据变化时就会重新执行依赖相关的渲染函数,实现视图的更新。

1.Vue 2 的响应式系统
        在 Vue 2 中,响应式系统基于 Object.defineProperty 来实现。对于每个响应式数据对象,Vue 都会递归遍历其所有属性,并使用 Object.defineProperty 将它们转换为 getter/setter 形式。当属性被访问时,getter 方法会被调用;当属性被修改时,setter 方法会被调用。这些方法内部会记录依赖关系,并在数据变化时通知观察者更新视图。

数据观测:当 Vue 实例创建时,它会遍历 data 对象的所有属性,并使用 Object.defineProperty 将每个属性转换为响应式的。这个过程由 Observer 类完成。

依赖收集:当模板渲染或计算属性计算时,Vue 会追踪哪些数据被访问了。这通过 Dep 类和 Watcher 类完成。Watcher 会在读取数据时将自身添加到数据的依赖列表中。

数据变更通知:当数据被修改时,对应的 Watcher 会收到通知,并触发视图更新。

2.Vue 3 的响应式系统
        Vue 3 引入了新的响应式 API,使用 Proxy 替代了 Object.defineProperty。这提供了更高效、更简洁的解决方案,同时也更好地支持了现代浏览器(ES6)。

数据包装:在 Vue 3 中,响应式数据不再是直接修改的原生对象,而是通过 reactive 函数包装后的代理对象。这个代理对象使用 Proxy 创建,可以拦截所有的读取和写入操作。

读取操作的追踪:当访问响应式数据的属性时,Proxy 的 get 方法会被调用,Vue 的响应式系统会记录下这次读取操作,并将其与当前的副作用函数(effect)关联起来。

写入操作的追踪:当修改响应式数据的属性时,Proxy 的 set 方法会被调用,Vue 的响应式系统会检查哪些副作用函数依赖于这个属性,并将它们标记为需要更新。

触发更新:当执行到被标记为需要更新的副作用函数时,Vue 的调度器会确保它们重新执行,从而触发视图的更新。这个过程通常是异步的,以提高性能。

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

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

相关文章

领夹麦买哪个牌子的好用点?一文看懂领夹麦克风什么牌子的好

自媒体时代的兴起&#xff0c;给了普通人很多的机会&#xff0c;尤其短视频的兴起更是让无数热情&#xff0c;有创作之心的人跃跃欲试。于是乎越来越多的人纷纷拿起了手机到各个平台去展示自己的才华&#xff0c;或者通过vlog记录分享自己的简单生活。 不过在分享和创作的输出时…

MYSQL 将某个字段赋值当前时间

如 我们需要将use_time 赋值为当前时间&#xff1a; 准备三条数据 &#xff1a; 执行sql &#xff0c;2种当前时间赋值函数&#xff0c;1种关键字赋值 &#xff1a; update test_info SET use_timeNOW() WHERE id 1; update test_info SET use_timeCURRENT_TIMESTAMP() …

React+TS前台项目实战(十九)-- 全局常用组件封装:带加载状态和清除等功能的Input组件实现

文章目录 前言Input组件1. 功能分析2. 代码详细注释3. 使用方式4. 效果展示 总结 前言 今天我们来封装一个input输入框组件&#xff0c;并提供一些常用的功能&#xff0c;你可以选择不同的 尺寸、添加前缀、显示加载状态、触发回调函数、自定义样式 等等。这些功能在这个项目中…

【面试干货】Java中==和equals()的区别

【面试干货】Java中和equals&#xff08;&#xff09;的区别 1、操作符2、equals()方法3、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java中&#xff0c;和equals()是两个常用的比较操作符和方法&#xff0c;但它们之间的用法和…

微服务+云原生:打造高效、灵活的分布式系统

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《未来已来&#xff1a;云原生之旅》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、云原生概述 2、微服务概述 二、微服务架构基础 1、…

springboot学习03-[Spring Boot与Web开发]

Spring Boot与Web开发 RestTemplateMockMvc在SPringBoot中使用 SpringBoot整合swagger2SpringBoot的springmvc自动配置底层原理包含ContentNegotiatingViewResolver和BeanNameViewResolverContentNegotiatingViewResolverBeanNameViewResolver 支持提供静态资源&#xff0c;包括…

Firefox 编译指南2024 Windows10篇- 源码获取(二)

1. 引言 在成功准备了编译环境之后&#xff0c;下一步就是获取Firefox的源码。源码是编译任何软件的基础&#xff0c;对于开源项目如Firefox尤其重要。通过获取并理解源码&#xff0c;开发者不仅能够编译出自定义版本的Firefox&#xff0c;还能对其进行修改和优化&#xff0c;…

element-ui侧边栏:default-openeds

element-ui侧边栏实现路由跳转后展开对应侧边栏&#xff1a;default-openeds 当菜单是在本地写死时&#xff0c;如果想展开第一块内容、里面就只写1 :default-openeds"[‘1’]" 当菜单是动态获取时&#xff0c;点击跳转之后如何展开对应的菜单&#xff0c;在watch中监…

如何提高pcdn技术的传输效率?

提高PCDN技术的传输效率是一个复杂且多层面的任务&#xff0c;涉及多个关键策略和方法的结合。以下是一些具体的建议和措施&#xff0c;有助于提升PCDN技术的传输效率&#xff1a; 一&#xff0e;优化缓存策略&#xff1a; 精准定位热点内容&#xff0c;优先将这部分内容缓存…

Unity Apple Vision Pro 开发(三):visionOS 应用形态

文章目录 &#x1f4d5;教程说明&#x1f4d5;常用名词解释&#x1f4d5;visionOS 空间类型⭐Shared Space 共享空间⭐Full Space/Immersive Space 独占空间 &#x1f4d5;visionOS 渲染框架&#x1f4d5;Unity 开发 visionOS 应用的不同模式⭐**窗口模式**⭐VR 模式⭐MR 模式 …

Python数据分析-电信客户流量预测与分析

一、背景介绍 研究背景&#xff1a;在快速发展和高度竞争的电信行业中&#xff0c;客户流失已成为运营商面临的主要挑战之一。电信服务的普及和用户选择的多样性使得保持客户忠诚度变得越来越困难。在这种背景下&#xff0c;准确预测客户流失并采取相应措施&#xff0c;对于运…

深入理解Java中的Collectors(Stream流)

引言 在 Java 的 Stream API 中&#xff0c;Collectors 是一个非常强大的工具类&#xff0c;它提供了许多静态方法&#xff0c;用于将 Stream 的元素收集到集合、字符串或其他类型的结果中。使用 Collectors&#xff0c;我们可以轻松地进行数据聚合和转换操作。 文章目录 引言…

【threejs】火焰特效制作

2024-06-26 08-57-16火焰 shader 来源 //shadertory&#xff1a;https://www.shadertoy.com/view/ctVGD1//shadertory&#xff1a;https://www.shadertoy.com/view/ml3GWs 代码 import { DoubleSide, ShaderChunk, ShaderMaterial } from "three";export default fu…

华为OD机试【高矮个子排队】(java)(100分)

1、题目描述 现在有一队小朋友&#xff0c;他们高矮不同&#xff0c;我们以正整数数组表示这一队小朋友的身高&#xff0c;如数组{5,3,1,2,3}。 我们现在希望小朋友排队&#xff0c;以“高”“矮”“高”“矮”顺序排列&#xff0c;每一个“高”位置的小朋友要比相邻的位置高或…

利用BFS解决每个零售店到仓库最短距离之和问题

1、题目 矩阵中有3种类型&#xff1a;0仓库&#xff0c;-1障碍&#xff0c;1零售店。现在每个零售店要去距离它最近的仓库取货物&#xff0c;请计算出所有零售店到最近仓库距离之和&#xff0c;假设矩阵中每个单元格之间距离为1。如果遇到障碍物&#xff0c;则表示无法通过。可…

图神经网络实战(15)——SEAL链接预测算法

图神经网络实战&#xff08;15&#xff09;——SEAL链接预测算法 0. 前言1. SEAL 框架1.1 基本原理1.2 算法流程 2. 实现 SEAL 框架2.1 数据预处理2.2 模型构建与训练 小结系列链接 0. 前言 我们已经学习了基于节点嵌入的链接预测算法&#xff0c;这种方法通过学习相关的节点嵌…

2024年上半年软件设计师上午真题及答案解析

1.在计算机网络协议五层体系结构中&#xff0c;( B )工作在数据链路层。 A.路由器 B.以太网交换机 C.防火墙 D.集线器 网络层&#xff1a;路由器、防火墙 数据链路层&#xff1a;交换机、网桥 物理层&#xff1a;中继器、集线器 2.软件交付之后&#xff…

数据可视化期末考试(编程)

1.KNN 1.新增数据的分类 import pandas as pd # 您的原始数据字典 data { 电影名称: [电影1, 电影2, 电影3, 电影4, 电影5], 打斗镜头: [10, 5, 108, 115, 20], 接吻镜头: [110, 89, 5, 8, 200], 电影类型: [爱情片, 爱情片, 动作片, 动作片, 爱情片] } …

uni-app uni-data-picker级联选择器无法使用和清除选中的值

出现问题&#xff1a; 使用点击右边的叉号按钮无法清除已经选择的uni-data-picker值 解决办法&#xff1a; 在uni-app uni-data-picker使用中&#xff0c;要添加v-model&#xff0c;v-model在官网的示例中没有体现&#xff0c;但若不加则无法清除。 <uni-data-picker v-m…

OpenAI用GPT-4o打造癌症筛查AI助手;手机就能检测中风,准确率达 82%!中国气象局发布AI气象大模型...

AI for Science 企业动态速览—— * 皇家墨尔本大学用 AI 检测患者中风&#xff0c;准确率达 82% * OpenAI 用 GPT-4o 模型打造癌症筛查 AI 助手 * 中国气象局发布 AI 气象大模型风清、风雷、风顺 * AI 药企英矽智能&#xff1a;小分子抑制剂已完成中国 IIa 期临床试验全部患者…