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,一经查实,立即删除!

相关文章

kafka 集群原理设计(二)之源码设计示例分析

kafka 集群原理设计(二)之源码设计示例分析 将通过提供详细的 Java 实现示例来说明 Kafka 集群的工作原理,重点介绍如何通过 ZooKeeper 实现多个 Broker 共同工作,接收、存储和传递消息,以及如何将数据分布在多个节点,实现负载均 衡和高可用性。 Kafka 集群原理设计和实…

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

自媒体时代的兴起&#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;你可以选择不同的 尺寸、添加前缀、显示加载状态、触发回调函数、自定义样式 等等。这些功能在这个项目中…

后端技术实战案例总结:从单体应用到微服务架构的迁移

在我多年的后端开发生涯中&#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;包括…

【Python基础】pprint:将 Python 对象美观地打印出来

pprint 是 Python 标准库中的一个模块,全称为 “Pretty Printer”。顾名思义,pprint 的主要功能是将 Python 对象美观地打印出来。这对于打印复杂的数据结构如字典、列表、集合等,尤其是当这些数据结构嵌套较深且包含多个元素时,非常有用。使用 pprint 可以使输出更加易读,…

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 模式 …

PostgreSQL 高级SQL查询(三)

1. JOIN 操作 1.1 内连接&#xff08;INNER JOIN&#xff09; 内连接用于返回两个表中存在匹配关系的记录。基本语法如下&#xff1a; SELECT columns FROM table1 INNER JOIN table2 ON table1.column table2.column;例如&#xff0c;从 users 表和 orders 表中检索所有用…

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

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

KVM配置嵌套虚拟化

按照以下步骤启用、配置和开始使用嵌套虚拟化,默认情况下禁用该功能,要启用它,请在宿主机物理机上进行配置。在centos stream 9和ubuntu 22部署kvm默认支持虚拟机嵌套虚拟化。 1、英特尔 1.1检查嵌套虚拟化在您的主机系统上是否可用 $cat /sys/module/kvm_intel/paramete…

深入理解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…

4、广告-考核标准

在程序化广告中&#xff0c;评估广告效果是衡量广告活动成功与否的关键。本章将详细介绍广告效果的定义、层次和评估方法&#xff0c;并提供中文名词与英文名词的一一对应。 一、广告效果的定义&#xff08;Definition of Advertising Effectiveness&#xff09; 广告效果是指…

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

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