理解vue2中的watch监听

  1. vue实例组件初始化过程中,在执行initState(vm)方法初始化状态时,判断options.watch有值时会进行initWatch(vm, options.watch)处理,然后对watch对象中的每个watch属性执行createWatcher方法
function initState(vm) {// 传入的watchif (options.watch) { initWatch(vm, options.watch)}
}
function initWatch(vm, watch) {for (let key in watch) {let handler = watch[key]// 这里不写数组的情况了,平时没用过createWatcher(vm, key, handler)}
}
  1. 执行createWatcher方法,拿到watch属性的具体回调函数,再执行vm.$watch方法
function createWatcher(vm, expOrFn, handler, options) {// 对象if (handler.toString() === '[object Object]') {options = handlerhandler = handler.handler}// 监听的方法是methods里的方法if (typeof handler === 'string') {handler = vm[handler]}return vm.$watch(expOrFn, handler, options)
}
  1. 执行$watch方法,给属性创建一个对应的watcher观察者实例,用来依赖收集。如果设置了immediate:true标识,表示立即执行一次回调函数
Vue.prototype.$watch = function (expOrFn, cb, options) {options = options || {}// 用户自己设置的watchoptions.user = true let watcher = new Watcher(this, expOrFn, cb, options)// 立即执行if (options.immediate) {pushTarget();cb.apply(this, [watcher.value])popTarget();}
}
  1. 创建watcher实例,进行依赖收集。如果watch的属性是定义在data中的,此watcher实例会被push进data中对应的属性的Dep对象的subs数组中。如果watch的属性是计算属性,此watcher实例会被push进计算属性中所有响应式数据的Dep对象的subs数组中
class Watcher {constructor(vm, expOrFn, cb, options) {//...if (options) {this.user = !!options.user;this.deep = !!options.deep; // 是否深度监听this.lazy = !!options.lazy;}this.vm = vm;this.cb = cb; // 回调函数this.active = true;// 获取watch属性在vm实例上对应的值this.getter = parsePath(expOrFn); this.value = this.lazy ? undefined : this.get();}get() {pushTarget(this);let vm = this.vm;let value = this.getter.call(vm, vm);// 深度监听if (this.deep) {traverse(value);}popTarget();return value;}update() {// 进入异步队列,这个之前讲过,会触发this.run()queueWatcher(this);}run() {let value = this.get();if (value !== this.value || isObject(value) || this.deep) {let oldValue = this.value;this.value = value;if (this.user) {// 执行回调函数this.cb.apply(this.vm, [value, oldValue]);}}}
}// 获取watch属性在vm实例上对应的值
// 可以是data中定义的属性,也可以是计算属性
function parsePath(path) {let segments = path.split(".");return function (obj) {if (!obj) return;for (let i = 0; i < segments.length; i++) {obj = obj[segments[i]];}return obj;};
}
function isObject(obj) {return obj !== null && typeof obj === "object";
}// 递归处理触发每一个属性的getter,形成深度依赖收集
let seenObjects = new Set();
function traverse(val) {_traverse(val, seenObjects);seenObjects.clear(); // 清空return val;
}
function _traverse(val, seen) {let i;let keys;if (val.__ob__) {var depId = val.__ob__.dep.id;// 处理循环引用的情况if (seen.has(depId)) {return;}seen.add(depId);}if (Array.isArray(val)) {i = val.length;while (i--) _traverse(val[i], seen);} else {keys = Object.keys(val);i = keys.length;// 触发响应式数据的getterwhile (i--) _traverse(val[keys[i]], seen);}
}
  1. 当监听的响应式数据发生变化时,触发watcher.update()方法,最终执行watcher.run()方法,执行回调函数。

总结:watch与computed的区别

  1. watch无缓存功能,所监听的响应式属性值发生变化时,都会立即触发回调函数;
  2. watch更灵活,可以监听任何响应式数据或表达式的变更;
  3. watch支持深度监听,可支持在回调函数中执行异步操作,如网络请求等等。适用场景:数据变更后执行自定义逻辑,如网络请求、DOM操作。需要监听深层对象结构变化时。
  4. computed依赖其他数据属性进行计算,并返回计算结果,必须return出去一个值;
  5. computed具有缓存功能,计算结果进行缓存,提高性能。适用场景:所需的值是要根据多个响应式属性计算得出,并且会被频繁使用的值;

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

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

相关文章

华为OD机试 - 最多颜色的车辆(Java JS Python C C++)

须知 哈喽,本题库完全免费,收费是为了防止被爬,大家订阅专栏后可以私信联系退款。感谢支持 文章目录 须知题目描述输入描述输出描述解析代码题目描述 在一个狭小的路口,每秒只能通过一辆车,假设车辆的颜色只有 3 种,找出 N 秒内经过的最多颜色的车辆数量。 三种颜色编…

线程与Task的区别 async和await关键字

任务Task和线程Thread的区别&#xff1a; 1、任务是架构在线程之上的&#xff0c;也就是说任务最终还是要抛给线程去执行。 2、任务跟线程不是一对一的关系&#xff0c;比如开10个任务并不是说会开10个线程&#xff0c;这一点任务有点类似线程池&#xff0c;但是任务相比线程池…

C++初阶---vector(STL)

1、vector的介绍和使用 1.1、vector的介绍 1. vector是表示可变大小数组的序列容器。 2. 就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素 进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;它的大小是…

为什么你选择成为一名程序员?

成为一名程序员&#xff0c;是基于多种因素的考量。 首先&#xff0c;对技术和创新的热爱是关键因素之一。编程是一种创造的过程&#xff0c;能够将抽象的想法转化为实际的应用程序和系统&#xff0c;这种创造的满足感令人着迷。 其次&#xff0c;编程领域的广阔发展前景也是…

MATLAB 普通场景的道路点云分割 (方法一)(56)

MATLAB 普通场景的道路点云分割(方法一) (56) 一、分割原理二、算法实现1.代码一、分割原理 基于这样一个认识:大部分情况下,点云都是分块去处理的,在某块点云场景中,点云区域不大,地面基本是水平分布的,不会有较大的坡度,因此将其认为是一个法向与Z轴大致平行的平…

前端开发语言种类说明

前端开发主要涉及的语言包括HTML、CSS、JavaScript&#xff0c;以及TypeScript和JQuery等流行工具和框架。这些语言和技术的详细介绍如下&#xff1a;12 HTML&#xff08;HyperText Markup Language&#xff09;。HTML是用于构建Web页面的标记语言&#xff0c;用于定义页面的结…

Python空间分析简明教程

数据世界是一个活生生的、会呼吸的事物。 当一个城市的犯罪率上升时&#xff0c;这是因为现实世界中有人在某个地方犯罪。 有警察局、住宅区和商业区、人口密度以及可以与位置相关联的人的地方。 所有这些东西都存在于数据框和表格之外的世界中。 空间分析使数据科学家能够回答…

实战环境-Activiti7从入门到专家(4)

背景 对于activiti7 已经有了感性认知&#xff0c;并且已经获得了源代码&#xff0c;梳理了核心的API。后面还有大量的内容&#xff0c;包括BPMN规范的落地&#xff0c;但是我们不能只停留在理论层次&#xff0c;需要从实际罗德的内容展开&#xff0c;因此需要构建实战环境。 …

WD西部数据正式通知客户:HDD与NAND继续涨价!

人工智能&#xff08;AI&#xff09;市场的快速增长引发了对数据存储的巨大需求。加之去年因市场环境因素导致HDD制造商减产&#xff0c;自去年下半年以来&#xff0c;高容量HDD供不应求&#xff0c;致使整体HDD价格显著上涨。据TechNews援引的行业消息指出&#xff0c;自去年第…

【测试开发学习历程】python高阶函数

目录 1 map()函数 2 reduce()函数 3 filter()函数 4 sorted()函数 1 map()函数 map()函数语法&#xff1a;map(function,iterable) 参数&#xff1a; function&#xff1a;函数 iterable&#xff1a;一个或多个序列 返回值&#xff1a;迭代器对象 作用&#xff1a;map(…

[每日算法 - 阿里机试] leetcode739. 每日温度

入口 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/daily-temperatures/descr…

定义一个函数:将输入字符串中最长的单词输出

#include <stdio.h> #include <string.h> int main(){ // 定义一个函数&#xff0c;用于判断字符是否为字母 int ab(char); // 定义一个函数&#xff0c;用于返回字符串中连续字母的最大长度起始位置 int lg(char[]); int i; char str[100…

windows安装charles抓包iphone

安装charles抓包iphone charles基础介绍windows安装 charles基础介绍 Charles 是在 PC 端常用的网络封包截取工具&#xff0c;在做移动开发时&#xff0c;我们为了调试与服务器端的网络通讯协议&#xff0c;常常需要截取网络封包来分析。除了在做移动开发中调试端口外&#xf…

不允许在constexpr函数中进行声明

这是我用pycharm在windows系统下复现sfm深度学习网络(Deep Two-View Structure-from-Motion Revisited&#xff09;遇见的问题&#xff0c;复现时有段代码pytorch扩展cuda/c&#xff0c;pycharm中出现C标准相关的报错如下&#xff1a; 在网上查找很久无果&#xff0c;后面通过…

strlen的模拟实现详解(三种办法)

文章目录 概要整体架构流程代码实现小结 概要 通过指针的运用和递归函数通过三种办法模拟实现strlen的功能 整体架构流程 第一种&#xff1a;&#xff08;计数器版&#xff09;通过指针的计算字符串的长度&#xff0c;通过while循环条件是指针不等于\0&#xff0c;来实现指针…

sipp单机压测freeswitch第4篇压测点对点呼叫

SIPp压测点对点呼叫&#xff0c;主要是使用官方提供的g711a.pcap模拟语音发起&#xff0c;在呼叫成功后Freeswitch播放一个音频文件可以是wav,SIPp后续开启Rtp回显功能&#xff0c;模拟双方相互发言 audioCall脚本xml 脚本大概意思是&#xff1a;发起成功后执行5分钟后自己挂断…

关于VMware虚拟机支不支持睿频技术的讨论

文章目录 概要名词解释超线程技术睿频技术虚拟化技术 整体测试流程测试平台 小结 概要 最近一直在研究基于Linux的虚拟机&#xff0c;目前看起来效果比在Windows上略差点&#xff0c;还没找到原因。我偶然发现在VMware这个虚拟机OS上CPU频率不对&#xff0c;我在疑惑这对于虚拟…

nginx配置实例-高可用主备模式

目录 什么是高可用&#xff1f; 解决的问题&#xff1f; 双机热备方案 keepalived是什么&#xff1f; 故障转移机制 环境准备 一、实现过程 1.1安装keepalived 安装好以后&#xff0c;将keepalived程序开启&#xff0c;并且加入到开机启动项中 1.2修改主机&#xff08;…

winform入门篇3 -- 手工创建窗口

手工创建窗口 Form, 窗口 可以手工创建一个窗口类 class MyFrom : Form { } 1.创建一个windows 窗体应用 这样就自动创建了一个窗体应用Form1 现在不使用这个自动创建的&#xff0c;手工写一个 2.手动创建 1.删除Form1.cs 2.添加 新建MyForm 类 让该类继承Form 在构造…

Covalent Network(CQT)推出以太坊质押迁移计划,以增强长期结构化数据可用性、塑造万亿级 LLM 参数体系

作为 Web3 领先的链上数据层&#xff0c;Covalent Network&#xff08;CQT&#xff09;宣布了其将质押操作从 Moonbeam 迁移回以太坊的决定。此举是 Covalent Network&#xff08;CQT&#xff09;走向以太坊时光机&#xff08;EWM&#xff09;的第一步&#xff0c;EWM 是一个为…