Vue响应式之Object变化侦测原理

news/2024/9/22 12:42:00/

核心代码 

javascript">//Dep类用来收集依赖、删除依赖、通知依赖更新
class Dep {constructor() {this.subs = [];}addSub(sub) {this.subs.push(sub);}notify() {this.subs.forEach(sub => sub.update());}removeSub(sub) {const index = this.subs.indexOf(sub);if (index > -1) {this.subs.splice(index, 1);}}
}// Observer类将data对象内的所有属性(包括子属性)都转换成getter/setter的形式,所以可侦测每个属性的变化
class Observer {constructor(data) {this.data = data;if (!Array.isArray(data)) {this.walk(data);}}walk(obj) {Object.keys(obj).forEach(key => {this.defineReactive(obj, key, obj[key]);});}defineReactive(data, key, val) {if (typeof val === 'object') { //递归子属性new Observer(val);}let dep = new Dep();Object.defineProperty(data, key, {enumerable: true,configurable: true,get() {dep.addSub(window.target);return val;},set(newValue) {if (newValue === val) {return;}val = newValue;dep.notify();}});}
}//Watcher实例即为上面所说的依赖,也就是我们常说的订阅者
class Watcher {constructor(vm, exp, cb) {this.vm = vm;  // ViewModel 的实例this.exp = exp;  // 要观察的数据属性的表达式(即字符串)this.cb = cb;  // 当数据属性变化时要调用的回调函数this.value = this.get();  // 初始化时获取数据属性的值}get() {window.target = this;  // 临时将当前 Watcher 实例设置为全局目标const value = this.vm[this.exp];  // 使用 exp 从 vm 中获取属性值(此时会触发getter)window.target = null;  // 清除全局目标return value;  // 返回获取到的属性值}update() {const value = this.get();//获取新值// 只有当新值和旧值不同时才调用回调函数并更新旧值if (value !== this.value) {this.value = value;this.cb.call(this.vm, value);}}
}

Watcher原理

先把自己设置到全局唯一的指定位置(如window.target),然后读取数据。因为读取了数据,所以会触发这个数据的getter。接着,在getter中就会从全局指定位置获取当前正在读取数据的Watcher实例,并把这个Watcher实例收集到Dep中。通过这样的方式,Watcher可以主动去订阅任意一个数据的变化。

总结

data通过Observer转换成了getter/setter的形式来追踪变化。

当外界通过watcher读取数据时,会触发getter从而将watcher实例(依赖)添加到该数据的专属Dep实例中。

当数据发生变化时,会触发该数据的setter,从而向Dep中的依赖发送通知。watcher接收到通知后,会向外界发送通知,变化通知到外界后可能会触发试图更新,也有可能触发用户的某个回调函数(调用Dep中的notify方法,遍历执行所有watcher实例上的update方法)。


http://www.ppmy.cn/news/1528815.html

相关文章

Vue3:v-model实现组件通信

目录 一.性质 1.双向绑定 2.语法糖 3.响应式系统 4.灵活性 5.可配置性 6.多属性绑定 7.修饰符支持 8.defineModel使用 二.使用 1.父组件 2.子组件 三.代码 1.父组件代码 2.子组件代码 四.效果 一.性质 在Vue3中,v-model指令的性质和作用主要体现在…

Sqlmap中文使用手册 - File system access模块参数使用

目录 1. File system access模块的帮助文档2. 各个参数的介绍2.1 --file-readFILE2.2 --file-writeFILE2.3 --file-destFILE 1. File system access模块的帮助文档 File system access:These options can be used to access the back-end database managementsystem underlying…

IT行业:未来发展的无限可能

IT行业:未来发展的无限可能 近年来,IT行业的快速发展给各行各业带来了深远的影响。从软件开发、网络安全到云计算、大数据,IT技术正在改变我们的工作方式和生活方式。尽管这一领域已经取得了长足的进步,但未来依然充满了创新和探…

拥控算法BBR入门1

拥塞控制算法只与本地有关 一个TCP会话使用的拥塞控制算法只与本地有关。 两个TCP系统可以在TCP会话的两端使用不同的拥塞控制算法 Bottleneck Bandwidth and Round-trip time Bottleneck 瓶颈 BBR models the network to send as fast as the available bandwidth and is 2…

CVE-2024-46103

前言 CVE-2024-46103 SEMCMS的sql漏洞。 漏洞简介 SEMCMS v4.8中,SEMCMS_Images.php的search参数,以及SEMCMS_Products.php的search参数,存在sql注入漏洞。 (这个之前就有两个sql的cve,这次属于是捡漏了&#x1f6…

【有啥问啥】自动提示词工程(Automatic Prompt Engineering, APE):深入解析与技术应用

自动提示词工程(Automatic Prompt Engineering, APE):深入解析与技术应用 引言 随着大语言模型(LLM)如 GPT、BERT 等的快速发展,如何高效地与这些模型进行互动成为了重要的研究方向之一。提示词&#xff…

Vue.js与Flask/Django后端配合

Vue.js与Flask/Django后端配合 在现代Web开发领域,前后端分离已成为一种流行的架构模式。Vue.js作为一款轻量级、高性能的前端框架,与Flask或Django这样的后端框架相结合,可以构建出强大且可扩展的Web应用。本文将详细介绍如何将Vue.js与Fla…

MySQL深入原理

MySQL深入原理 索引、事务、日志原理、InnoDB引擎、缓存、锁 有4个数据库是属于MySQL自带的系统数据库: ​ mysql MySQL 系统自带的核心数据库,它存储了MySQL的用户账户和权限信息,一些存储过程、事件的定义信息,一些运行过程中…