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

vue2源码解析---watch和computed

监听属性watch

监听属性介绍

我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数wach 可以用于异步任务

监听属性的初始化

watch和computed都先走initSate判断传入选项

export function initState(vm) {const opts = vm.$options; // 获取所有的选项if (opts.data) {initData(vm);}if (opts.computed) {initComputed(vm);}if (opts.watch) {initWatch(vm);}
}

接下来initWatch进入此函数

function initWatch(vm){let watch = vm.$options.watch;for(let key in watch){const handler = watch[key]; // 字符串 数组 函数if(Array.isArray(handler)){for(let i = 0; i < handler.length;i++){createWatcher(vm,key,handler[i]);}}else{createWatcher(vm,key,handler);}}}

通过原型方法$watch传入处理参数创建一个观察者收集依赖变化。

function createWatcher(vm,key,handler){// 字符串  函数if(typeof handler === 'string'){handler = vm[handler];}return vm.$watch(key,handler)
}

原型上的$watch函数

export function initStateMixin(Vue) {Vue.prototype.$nextTick = nextTick;// 最终调用的都是这个方法Vue.prototype.$watch = function (exprOrFn, cb) {// firstname// ()=>vm.firstname// firstname的值变化了 直接执行cb函数即可new Watcher(this, exprOrFn, { user: true }, cb)}
}

计算属性computed

计算属性介绍

计算属性是在 Vue 实例的computed选项中定义的,可以是一个函数或具有get和set方法的对象。函数形式的计算属性会在调用时被执行,而对象形式的计算属性则可以提供自定义的get和set方法
计算属性适用于那些依赖其他响应式数据的场景,而不适用于需要进行异步操作或有副作用的场景。对于这些情况,可以使用侦听器(watcher)或使用methods来处理。

计算属性实现过程

计算属性的初始化

1 在initComputed函数中,遍历计算属性对象,为每个计算属性创建一个Watcher实例,并将其存储在vm._computedWatchers中。

export function initState(vm) {const opts = vm.$options; // 获取所有的选项if (opts.data) {initData(vm);}if (opts.computed) {initComputed(vm);}if (opts.watch) {initWatch(vm);}
}
function initComputed(vm) {const computed = vm.$options.computed;const watchers = vm._computedWatchers = {}; // 将计算属性watcher保存到vm上for (let key in computed) {//获取用户定义的计算属性let userDef = computed[key];// 我们需要监控 计算属性中get的变化let fn = typeof userDef === 'function' ? userDef : userDef.get// 如果直接new Watcher 默认就会执行fn, 将属性和watcher对应起来 watchers[key] = new Watcher(vm, fn, { lazy: true })defineComputed(vm, key, userDef);}
}
属性劫持

2 defineComputed 方法主要是重新定义计算属性,其实最主要的是劫持get方法。
为啥要劫持呢? 因为我们需要根据依赖值是否发生变化来判断计算属性是否需要重新计算

function defineComputed(target, key, userDef) {// const getter = typeof userDef === 'function' ? userDef : userDef.get;const setter = userDef.set || (() => { })// 可以通过实例拿到对应的属性Object.defineProperty(target, key, {get: createComputedGetter(key),set: setter})
}

3 createComputedGetter判断计算属性的值是否变化 增加dirty
如果是true执行更新

// 计算属性根本不会收集依赖 ,只会让自己的依赖属性去收集依赖
function createComputedGetter(key) {// 我们需要检测是否要执行这个getterreturn function () {const watcher = this._computedWatchers[key]; // 获取到对应属性的watcherif (watcher.dirty) {// 如果是脏的就去执行 用户传入的函数watcher.evaluate(); // 求值后 dirty变为了false ,下次就不求值了}if (Dep.target) { // 计算属性出栈后 还要渲染watcher, 我应该让计算属性watcher里面的属性 也去收集上一层watcherwatcher.depend();//计算属性watcher收集渲染watcher}return watcher.value; // 最后返回的是watcher上的值}
}

watcher
新增了dirty属性 标识是否需要更新视图
增加了evaluate方法 重新渲染 并且将dirty变成true

// src/observer/watcher.js// import { pushTarget, popTarget } from "./dep";
// import { queueWatcher } from "./scheduler";
// import {isObject} from '../util/index'
// // 全局变量id  每次new Watcher都会自增
// let id = 0;export default class Watcher {constructor(vm, exprOrFn, cb, options) {// this.vm = vm;// this.exprOrFn = exprOrFn;// this.cb = cb; //回调函数 比如在watcher更新之前可以执行beforeUpdate方法// this.options = options; //额外的选项 true代表渲染watcher// this.id = id++; // watcher的唯一标识// this.deps = []; //存放dep的容器// this.depsId = new Set(); //用来去重dep// this.user = options.user; //标识用户watcherthis.lazy = options.lazy; //标识计算属性watcherthis.dirty = this.lazy; //dirty可变  表示计算watcher是否需要重新计算 默认值是true// 如果表达式是一个函数// if (typeof exprOrFn === "function") {//   this.getter = exprOrFn;// } else {//   this.getter = function () {//     //用户watcher传过来的可能是一个字符串   类似a.a.a.a.b//     let path = exprOrFn.split(".");//     let obj = vm;//     for (let i = 0; i < path.length; i++) {//       obj = obj[path[i]]; //vm.a.a.a.a.b//     }//     return obj;//   };// }// 非计算属性实例化就会默认调用get方法 进行取值  保留结果 计算属性实例化的时候不会去调用getthis.value = this.lazy ? undefined : this.get();}get() {pushTarget(this); // 在调用方法之前先把当前watcher实例推到全局Dep.target上const res = this.getter.call(this.vm); //计算属性在这里执行用户定义的get函数 访问计算属性的依赖项 从而把自身计算Watcher添加到依赖项dep里面收集起来popTarget(); // 在调用方法之后把当前watcher实例从全局Dep.target移除return res;}//   把dep放到deps里面 同时保证同一个dep只被保存到watcher一次  同样的  同一个watcher也只会保存在dep一次//   addDep(dep) {//     let id = dep.id;//     if (!this.depsId.has(id)) {//       this.depsId.add(id);//       this.deps.push(dep);//       //   直接调用dep的addSub方法  把自己--watcher实例添加到dep的subs容器里面//       dep.addSub(this);//     }//   }//   这里简单的就执行以下get方法  之后涉及到计算属性就不一样了update() {// 计算属性依赖的值发生变化 只需要把dirty置为true  下次访问到了重新计算if (this.lazy) {this.dirty = true;} else {// 每次watcher进行更新的时候  可以让他们先缓存起来  之后再一起调用// 异步队列机制queueWatcher(this);}}//   计算属性重新进行计算 并且计算完成把dirty置为falseevaluate() {this.value = this.get();this.dirty = false;}depend() {// 计算属性的watcher存储了依赖项的deplet i = this.deps.length;while (i--) {this.deps[i].depend(); //调用依赖项的dep去收集渲染watcher}}//   run() {//     const newVal = this.get(); //新值//     const oldVal = this.value; //老值//     this.value = newVal; //跟着之后  老值就成为了现在的值//     if (this.user) {//       if(newVal!==oldVal||isObject(newVal)){//         this.cb.call(this.vm, newVal, oldVal);//       }//     } else {//       // 渲染watcher//       this.cb.call(this.vm);//     }//   }
}

computed和watch的区别

**相同点:**底层都会创建一个watcher computed定义的属性可以在模板中使用 watch不能在视图中国使用
不同点: computed不会默认执行 只有取值会执行 内部会以一个dirty属性控制依赖的值是否变化
watch默认用户会提供一个回调函数 数据变化就使用用户传入的回调
本周总结
vue2手写部分学习完了 其实感觉收集依赖那一部分还是有点绕 后续应该会多看点别人总结的内容对着自己代码复习复习也学习了基础的webpack
下周主要还是学习一下源码 复习一下js高级啥的

相关文章:

vue2源码解析---watch和computed

监听属性watch 监听属性介绍 我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数wach 可以用于异步任务 监听属性的初始化 watch和computed都先走initSate判断传入选项 export function initState(vm) {const opts vm.$options; // 获取所有的选项if (opts.…...

【云原生】华为云踩坑日志(更新于2023.12.10)

1、华为云建议我们把sfs容量型升级到turbo版本&#xff0c;但是CCE产品storageclass sfs-turbo共享存储卷不支持动态绑定&#xff0c;官网文档可以实现动态创建子目录&#xff0c;建议大家直接选择这个&#xff0c;不要踩坑了 2、CCE 涉及到的产品&#xff0c;有的需要查看产品…...

计算机网络:自顶向下第八版学习指南笔记和课后实验--网络层(控制平面)

网络层&#xff1a;控制平面 记录一些学习计算机网络:自顶向下的学习笔记和心得 Github地址&#xff0c;欢迎star ⭐️⭐️⭐️⭐️⭐️ 控制平面作为一种网络范围的逻辑&#xff0c;不仅控制沿着从源主机到目的主机的端到端路径间的路由器如何转发数据报&#xff0c;而且控制…...

MFC 窗口创建过程与消息处理

目录 钩子简介 代码编写 窗口创建过程分析 消息处理 钩子简介 介绍几个钩子函数&#xff0c;因为它们与窗口创建工程有关 安装钩子函数 HHOOK SetWindowsHookExA([in] int idHook,[in] HOOKPROC lpfn,[in] HINSTANCE hmod,[in] DWORD dwThreadId ); 参数说明…...

基于JavaWeb+SSM+Vue微信小程序的移动学习平台系统的设计和实现

基于JavaWebSSMVue微信小程序的移动学习平台系统的设计和实现 源码获取入口Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 Lun文目录 第1章 绪论 1 1.1 课题背景 1 1.2 课题意义 1 1.3 研究内容 2 第2章 开发环…...

解决docker alpine /bin/sh: ./main: not found

解决docker alpine /bin/sh: ./main: not found golang中编译之后的二进制文件部署在alpine镜像中出现了not found问题解决这种情况是因为动态链接库位置错误导致的&#xff0c;alpine镜像使用的是musl libc而不是gun libc。因而动态链接库的位置不一致。在基础镜像内执行&…...

深入了解网络基础:从背景到协议

这里写自定义目录标题 1. 什么是协议呢&#xff1f;2. 什么是网络协议&#xff1f;5. OSI七层网络模型6. 网络传输基本流程1. 数据准备&#xff1a;2. 数据传输&#xff1a;3. 数据接收和重新组装&#xff1a;4. 数据处理与应用&#xff1a; 7. 数据的发送&#xff08;封装&…...

针对这两个趋势,3.0全新新零售商业模式可以采取以下策略:

国内市场确实存在“消费升级”和“消费降级”两个趋势&#xff0c;这是由于不同消费者群体的需求和购买力存在差异。消费升级主要发生在高端市场&#xff0c;消费者愿意为高品质、高价值、高价格的商品和服务付出更多。而消费降级则主要发生在中低端市场&#xff0c;消费者更加…...

鸿蒙HarmonyOS开发用什么语言

1.网上流行一句有中国底蕴的话&#xff1a;鸿蒙系统方舟框架盘古大模型。都方舟框架了肯定主推的是ArkUI框架。其实还能使用C、Java和Js开发。 2.从API8开始&#xff0c;Java语言已经从鸿蒙开发剔除了&#xff0c;而官方推荐的是ArkTs.下图是ArkTS与TS、JS的关系。 ArkTs 是TS的…...

气象数据预测分析与可视化:天气趋势预测揭秘

气象数据预测分析与可视化&#xff1a;天气趋势预测揭秘 引言数据获取数据分析可视化展示Flask框架实现创新点&#xff1a;空气质量预测结论 引言 天气对我们日常生活和工作有着重要的影响&#xff0c;因此天气预测与分析变得愈发重要。本文将介绍如何通过爬取2345天气网的数据…...

install cuda cudnn tersorRT

1, dark view 2,470-server cant install 11.4 3,cuda.run and tensorRT.dpkg cant # 安装 $ ubuntu-drivers devices$ sudo apt-get install nvidia-driver-470-server # 推荐是server&#xff0c;都可以。#delelt sudo apt --purge remove nvidia-* CUDA Toolkit Archiv…...

Vue 3 + Vite 4 移动端低版本白屏处理

vue3打包后在低版本浏览器或webview中出现白屏&#xff0c;原因就是因为语法兼容问题。根据vite官方文档描述&#xff0c;build.target 默认支持 Chrome >87、Firefox >78、Safari >14、Edge >88 传送&#xff0c;所以需要我们手动兼容低版本。 方法&#xff1a; …...

Python爬虫-解决使用requests,Pyppeteer,Selenium遇到网站显示“您的连接不是私密连接”的问题|疑难杂症解决(2)

前言 本文是该专栏的第13篇,后面会持续分享python爬虫案例干货,记得关注。 相信很多同学在处理爬虫项目的时候,会遇到一些网站出现如下图所示的情况: 就是当你不论是使用requests进行协议请求,还是使用自动化框架pyppeteer或者selenium都会出现上图中的情况。这相信会或多…...

机场信息集成系统系列介绍(5):机场运行资源管理系统

目录 一、简介 二、主要功能 1、 航班资源管理模块 2、甘特图资源模块 3、规划管理模块 4、资源基础数据定义及配置管理模块 5、系统功能设置模块 6、 审计管理模块 一、简介 机场运行资源管理系统(ORMS) 是一种专门用于管理和优化机场运行资源的系统。它能够实现机场航…...

JavaEE:线程池精讲

目录 一.什么是线程池 二.线程池的实现原理 &#x1f388;为什么要有工厂模式&#xff1f; 三.线程池的构造方法解读 &#x1f388;线程池的拒绝策略 四.自己实现一个线程池 一.什么是线程池 简单来说&#xff0c;线程池就好比一块鱼塘&#xff0c;鱼塘中的每条鱼就是一个线程…...

spring-cloud-starter-gateway-mvc的网关实现

一 概括 最近&#xff0c;我也一直在使用SpringCloudGateway开发我们自己的网关产品。根据我对官网文档&#xff1a;https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway-server-mvc.html 的理解&#xff0c;内容如下&#xff1a; SpringCloudGatew…...

《PySpark大数据分析实战》-11.Spark on YARN模式安装Hadoop

&#x1f4cb; 博主简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是wux_labs。&#x1f61c; 热衷于各种主流技术&#xff0c;热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员&#xff08;PCTA&#xff09;、TiDB数据库专家&#xff08;PCTP…...

多架构容器镜像构建实战

最近在一个国产化项目中遇到了这样一个场景&#xff0c;在同一个 Kubernetes 集群中的节点是混合架构的&#xff0c;也就是说&#xff0c;其中某些节点的 CPU 架构是 x86 的&#xff0c;而另一些节点是 ARM 的。为了让我们的镜像在这样的环境下运行&#xff0c;一种最简单的做法…...

通过层进行高效学习:探索深度神经网络中的层次稀疏表示

一、介绍 深度学习中的层次稀疏表示是人工智能领域日益重要的研究领域。本文将探讨分层稀疏表示的概念、它们在深度学习中的意义、应用、挑战和未来方向。 最大限度地提高人工智能的效率和性能&#xff1a;深度学习系统中分层稀疏表示的力量。 二、理解层次稀疏表示 分层稀疏表…...

自然语言处理阅读第二弹

HuggingFace 镜像网站模型库 HuggingFace中bert实现 下游任务介绍重要源码解读 NLP中的自回归模型和自编码模型 自回归&#xff1a;根据上文内容预测下一个可能的单词&#xff0c;或者根据下文预测上一个可能的单词。只能利用上文或者下文的信息&#xff0c;不能同时利用上…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...