当前位置: 首页 > news >正文

3.0 响应式系统的设计与实现

1、Proxy代理对象

Proxy用于对一个普通对象代理,实现对象的拦截和自定义,如拦截其赋值、枚举、函数调用等。里面包含了很多组捕获器(trap),在代理对象执行相应的操作时捕获,然后在内部实现自定义。

const data = {foo: 1}
// 代理data对象
const obj = new Proxy(data, {// obj元素赋值触发set(target, key, newValue){// 赋值自定义},// 读取obj元素值触发get(target, key){// 读取时自定义}
})

如上代码中obj对象为data对象的代理对象,此时obj内的元素和data一样,当在修改obj内部元素的时候会触发相应的捕获器,这样就可以实现自定义。

那么Proxy代理和响应式系统的设计有什么关系呢?请看以下关于副作用函数的介绍。

2、副作用函数

副作用函数是指会产生副作用的函数, 如:

function effect() {document.body.innerText = "hello world"
}

在执行effect函数时会改变body的文本内容,但是如果有其它函数会读取body的文本内容,这时body内容被effect函数修改了,就可以说effect在执行时产生了副作用,即如果一个函数的执行会直接或者间接的影响其他函数的执行就说这个函数产生了副作用

如果此时有这么一段代码:

const obj = {content: "hello world"}
function effect() {document.body.innerText = obj.content
}

在执行effect函数的时候会将obj.content的内容显示到body的文本内容中,那么如果我们每次修改obj.content的内容都会触发effect函数的执行,那么是不是就可以说obj.content是 一个响应式数据呢。

修改obj.content的内容然后触发effect函数,是不是使用就上面所述的Proxy代理即可实现,给obj进行代理,在修改content的值时会触发捕获器,此时我们可以在捕获器内自定义功能,就可以调用effect函数。

3、响应式数据的基本实现

接着上文思考,当obj变成了响应式数据会发生什么:

  1. 修改obj.content的值,这会触发effect函数的执行
  2. 触发effect函数,这会获取obj.content的值。

关于第二点触发effect函数一定会获取obj.content的值吗,这其实是肯定的,如果effect函数不会获取obj.content的值那么也就没有绑定的必要了。

使用代码也很容易实现,即:

// 原始对象
const data = {content: "hello world"}function effect() {document.body.innerText = obj.content
}const obj = new Proxy(data, {// 拦截读取操作,此时target为原始对象,key为元素键get(target, key) {return target[key]},// 拦截赋值操作set(target, key, newVal) {target[key] = newVal// 设置新值之后执行副作用函数effect()return true}
})// 修改后触发副作用函数
obj.content = 2

其执行逻辑也很简单,如图所示:

这里主要注意的是当原始对象被代理之后,与副作用函数交互的都是代理对象,而不是原始对象,此时修改原始对象是不会触发副作用函数的。

其实以上的设计并不完善,比如对象内元素的值影响的副作用函数并不止一个,这在开发中很常见,一个数据不一定仅仅绑定一个组件,以上的代码设计就太简单了。其实我们可以设计一个,将对象元素的副作用函数都加入桶中,当这个元素值被修改的时候将桶内的副作用函数全部拿出来执行。

代码如下:

// 用Set来模拟一个桶
const bucket = new Set()const data = {text: "hello world"}
function effect() {document.body.innerText = obj.text
}
const obj = new Proxy(data, {// 拦截读取操作,此时target为原始对象,key为元素键get(target, key) {// 在读取时,将副作用函数装进去bucket.add(effect)return target[key]},// 拦截赋值操作set(target, key, newVal) {target[key] = newVal// 设置新的值后取出所有副作用函数并执行bucket.forEach(fn => fn())return true}
})

以上就是一个非常简单且简陋的响应式系统,实现了响应式最基本的功能,但是其实还有非常多的问题都没有解决,如副作用函数是直接使用的effect函数名字获取,但是如果是匿名函数等无法获取,比如这个桶也非常的粗糙,将副作用函数完全塞进去,并没有细分,还有无限递归死循环问题等没有解决,这在之后的内容中会一一解决。

相关文章:

3.0 响应式系统的设计与实现

1、Proxy代理对象 Proxy用于对一个普通对象代理,实现对象的拦截和自定义,如拦截其赋值、枚举、函数调用等。里面包含了很多组捕获器(trap),在代理对象执行相应的操作时捕获,然后在内部实现自定义。 const…...

Rust 快速入门60分① 看完这篇就能写代码了

Rust 一门赋予每个人构建可靠且高效软件能力的语言https://hannyang.blog.csdn.net/article/details/130467813?spm1001.2014.3001.5502关于Rust安装等内容请参考上文链接,写完上文就在考虑写点关于Rust的入门文章,本专辑将直接从Rust基础入门内容开始讲…...

【5.JS基础-JavaScript的DOM操作】

1 认识DOM和BOM 所以我们学习DOM,就是在学习如何通过JavaScript对文档进行操作的; DOM Tree的理解 DOM的学习顺序 DOM的继承关系图 2 document对象 3 节点(Node)之间的导航(navigator) 4 元素&#xff0…...

【大数据之Hadoop】二十九、HDFS存储优化

纠删码和异构存储测试需要5台虚拟机。准备另外一套5台服务器集群。 环境准备: (1)克隆hadoop105为hadoop106,修改ip地址和hostname,然后重启。 vim /etc/sysconfig/network-scripts/ifcfg-ens33 vim /etc/hostname r…...

SuperMap GIS基础产品组件GIS FAQ集锦(2)

SuperMap GIS基础产品组件GIS FAQ集锦(2) 【iObjects for Spark】读取GDB参数该如何填写? 【解决办法】可参考以下示例: val GDB_params new util.HashMapString, java.io.Serializable GDB_params.put(FeatureRDDProviderParam…...

C语言printf()函数中整型格式说明符详解

每个整型在printf()函数中对应不同的格式说明符,以实现该整型的打印输出。格式说明符必须使用小写。现在让我们看看各个整型及其格式说明符: 短整型(short) 10进制:%hd16进制:无负数格式,正数使用%hx8进制:无负数格式,正数使用%ho c short s 34; printf("%hd", s…...

阿里云服务器地域和可用区怎么选择合适?

阿里云服务器地域和可用区怎么选择?地域是指云服务器所在物理数据中心的位置,地域选择就近选择,访客距离地域所在城市越近网络延迟越低,速度就越快;可用区是指同一个地域下,网络和电力相互独立的区域&#…...

Java序列化引发的血案

1、引言 阿里巴巴Java开发手册在第一章节,编程规约中OOP规约的第15条提到: **【强制】**序列化类新增属性时,请不要修改serialVersionUID字段,避免反序列失败;如果完全不兼容升级,避免反序列化混乱&#x…...

为Linux系统添加一块新硬盘,并扩展根目录容量

我的原来ubuntu20.04系统装的时候不是LVM格式的分区, 所以先将新硬盘转成LVM,再将原来的系统dd到新硬盘,从新硬盘的分区启动,之后再将原来的分区转成LVM,在融入进来 1:将新硬盘制作成 LVM分区 我的新硬盘…...

树莓派Opencv调用摄像头(Raspberry Pi 11)

前言:本人初玩树莓派opencv,使用的是树莓派Raspberry Pi OS 11,系统若不一致请慎用,本文主要记录在树莓派上通过Opencv打开摄像头的经验。 1、系统版本 进入树莓派,打开终端输入以下代码(查看系统的版本&…...

国产ChatGPT命名图鉴

很久不见这般热闹的春天。 随着ChatGPT的威名席卷全球,大洋对岸的中国厂商也纷纷亮剑,各式本土大模型你方唱罢我登场,声势浩大的发布会排满日程表。 有趣的是,在这些大模型产品初入历史舞台之时,带给世人的第一印象其…...

操作系统——进程管理

0.关注博主有更多知识 操作系统入门知识合集 目录 0.关注博主有更多知识 4.1进程概念 4.1.1进程基本概念 思考题: 4.1.2进程状态 思考题: 4.1.3进程控制块PCB 4.2进程控制 思考题: 4.3线程 思考题: 4.4临界资源与临…...

第四十一章 Unity 输入框 (Input Field) UI

本章节我们学习输入框 (Input Field),它可以帮助我们获取用户的输入。我们点击菜单栏“GameObject”->“UI”->“Input Field”,我们调整一下它的位置,效果如下 我们在层次面板中发现,这个InputField UI元素包含两个子元素&…...

10.集合

1.泛型 1.1泛型概述 泛型的介绍 ​ 泛型是JDK5中引入的特性&#xff0c;它提供了编译时类型安全检测机制 泛型的好处 把运行时期的问题提前到了编译期间避免了强制类型转换 泛型的定义格式 <类型>: 指定一种类型的格式.尖括号里面可以任意书写,一般只写一个字母.例如:…...

强化学习p3-策略学习

Policy Network (策略网络) 我们无法知道策略函数 π \pi π所以要做函数近似&#xff0c;求一个近似的策略函数 使用策略网络 π ( a ∣ s ; θ ) \pi(a|s;\theta) π(a∣s;θ) 去近似策略函数 π ( a ∣ s ) \pi(a|s) π(a∣s) ∑ a ∈ A π ( a ∣ s ; θ ) 1 \sum_{a\in …...

初学Verilog语言基础笔记整理(实例点灯代码分析)持续更新~

实例&#xff1a;点灯学习 一、Verilog语法学习 1. 参考文章 刚接触Verilog&#xff0c;作为一个硬件小白&#xff0c;只能尝试着去理解&#xff0c;文章未完…持续更新。 参考博客文章&#xff1a; Verilog语言入门学习&#xff08;1&#xff09;Verilog语法【Verilog】一文…...

关于 std::condition_variable

一. std::condition_variable是什么&#xff1f; std::condition_variable 是 C 标准库提供的一个线程同步的工具&#xff0c;用于实现线程间的条件变量等待和通知机制。 条件变量的发生通常与某个共享变量的状态改变相关。 在多线程编程中&#xff0c;条件变量通常和互斥锁…...

可拓展哈希

可拓展哈希 借CMU 15445的ppt截图来说明问题。 我们传统静态hash的过程是hash函数后直接将值存入对应的bucket&#xff0c;但是在可扩展hash中&#xff0c;得查询Directory&#xff08;左&#xff09;&#xff0c;存入directory指向的bucket&#xff08;右&#xff09;。 下面…...

Java 版 spring cloud 工程系统管理 +二次开发 工程项目管理系统源码

工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#xff1a;实现对数据字典标签的增删改查操作 2、编码管理&#xff1a;实现对系统编码的增删改查操作 3、用户管理&#xff1a;管理和查看用户角色 4、菜单管理&#xff1a;实现对系统菜单的增删改查操…...

通过伴随矩阵怎么求逆矩阵

设矩阵A为n阶方阵&#xff0c;其伴随矩阵为Adj(A)&#xff0c;则A的逆矩阵为&#xff1a; A⁻ (1/|A|) Adj(A) |A|为A的行列式 Adj(A)为A的伴随矩阵 具体步骤如下&#xff1a; 求出A的行列式|A| 求出A的伴随矩阵 Adj(A) 。伴随矩阵的定义为&#xff1a;对于A的第i行第j列…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...