当前位置: 首页 > 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列…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏&#xff0c;有着深厚的文化底蕴。通过将五子棋制作成网页游戏&#xff0c;可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家&#xff0c;都可以通过网页五子棋感受到东方棋类…...

实战设计模式之模板方法模式

概述 模板方法模式定义了一个操作中的算法骨架&#xff0c;并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下&#xff0c;重新定义算法中的某些步骤。简单来说&#xff0c;就是在一个方法中定义了要执行的步骤顺序或算法框架&#xff0c;但允许子类…...

云安全与网络安全:核心区别与协同作用解析

在数字化转型的浪潮中&#xff0c;云安全与网络安全作为信息安全的两大支柱&#xff0c;常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异&#xff0c;并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全&#xff1a;聚焦于保…...

何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡

何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践&#xff0c;很多人以为AI已经强大到不需要程序员了&#xff0c;其实不是&#xff0c;AI更加需要程序员&#xff0c;普通人…...

python打卡第47天

昨天代码中注意力热图的部分顺移至今天 知识点回顾&#xff1a; 热力图 作业&#xff1a;对比不同卷积层热图可视化的结果 def visualize_attention_map(model, test_loader, device, class_names, num_samples3):"""可视化模型的注意力热力图&#xff0c;展示模…...