学Vue3核心概念与面试官斗智斗勇(一) 收集触发依赖

2023-10-12 18:40

本文主要是介绍学Vue3核心概念与面试官斗智斗勇(一) 收集触发依赖,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文章依据阅读源码的理解进行编写。如果有什么错误的地方,欢迎指正交流学习。
最近也在帮助想入行前端的朋友进行学习,如果有需要交流学习,可以添加微信 gdgzyw
聊天、学习、打游戏都阔以~

学习源码最快的方式就是理解概念后,自己写一个简版的功能。所以我们得先搭一个环境,这里采用测试驱动的方式进行。

初始化项目

初始化 package.json 和安装依赖

yarn init -y
yarn add -D @babel/core @babel/preset-env @babel/preset-typescript @types/jest babel-jest jest

添加 scripts 用于启动 jest

package.json

{// ..."scripts": {"test": "jest"},// ...
}

根目录创建 babel.config.js

module.exports = {presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'],
}

创建 tsconfig.json 文件

{"compilerOptions": {"target": "es2016","lib": ["DOM","es6"],"module": "commonjs","types": ["jest"],"esModuleInterop": true,"forceConsistentCasingInFileNames": true,"strict": true,"noImplicitAny": false,"skipLibCheck": true}
}

至此我们的项目就初始化完成了。如果你需要用 git 来管理,可以自行 git init

编写测试用例

创建 src/reactivity/tests/effect.spec.ts 文件

describe('effect', () => {it('happy path', () => {const bank = reactive({money: 100,});let myMoney;effect(() => {myMoney = bank.money * 2;});expect(myMoney).toBe(200);bank.money = 50;expect(myMoney).toBe(100);});
});

创建 scr/reactivity/tests/reactive.spec.ts

describe('reactive', () => {it('happy path', () => {const origin = {money: 100};const bank = reactive(origin);expect(bank).not.toBe(origin);expect(bank.money).toBe(100);});
});

现在我们运行 yarn test 测试用例是跑不通的。对应的函数我们还没有创建。下面正式开始我们的编码环节。

编写 reactive 函数

通过上面的测试用例,我们可以知道,我们接收一个对象的值,并且对他进行一个拦截。所以我们可以直接返回一个 proxy 的代理对象。

export function reactive(obj) {return new Proxy(obj, {get(target, key) {return Reflect.get(target, key)},set(target, key, value) {return Reflect.set(target, key, value)},})
}

Reflect.get(target, key) 等同于 target[key]

接着我们为了统一出口可以创建 src/reactivity/index.ts 文件

index.ts

export * from './reactive'

接着我们去 reactive.spec.ts 中引入我们的函数

import {reactive} from '../index'

跑一下测试

yarn test reactive

提示 PASS 至此发现这个的单侧已经跑通。接着我们可以开始写另一个单测。

编写 effect 函数

一样的,我们观察一下测试用例的参数。
可以发现他接受一个回调,所以我们参数是一个回调函数。
接着我们思考一下如何将我们上一个 reactive 的函数与这个回调函数产生关联。

image.png

定义 tagetMap 变量,用于对象的分组。
定义 depsMap 变量,用于对象中每个 key 的依赖分组。
通过 reactive 定义对象,在 get 的时候,我们在 targetMap
中将对象添加到 Map 中作为分类。接着创建 Set 用 key 作为分类保存到 Set 中。

回顾我们的单侧流程,我们先定义了个 reactive 对象。
接着我们在 effect 函数中执行了回调函数,回调函数中我们会读取到 reactive 的值,从而触发了 get 操作。所以我们需要在 get 操作中进行依赖收集。

定义一个 ReactiveEffect 类,收集我们的回调函数

src/reactivity/effect.ts

let activeEffect
class ReactiveEffect {private readonly _fn: anyconstructor(fn) {this._fn = fn}run() {activeEffect = thisthis._fn()}
}export function effect(fn) {const _effect = new ReactiveEffect(fn)_effect.run()
}

在初始化的时候,我们保存回调函数到 _fn 中,在我们执行 run 方法的时候。会触发我们的回调函数。

定义一个 track 的函数,完成收集依赖这个操作

src/reactivity/effect.ts

const targetMap = new Map()
export function track(target, key) {let depsMap = targetMap.get(target)if (!depsMap) {depsMap = new Map()targetMap.set(target, depsMap)}let deps = depsMap.get(key)if (!deps) {deps = new Set()depsMap.set(key, deps)}deps.add(activeEffect)
}

如果此时我们需要设置 reactive 的值,我们会触发 set 操作。所以触发依赖的操作需要在 set 中进行。

定义 trigger 函数,触发所有依赖

export function trigger(target, key) {const depsMap = targetMap.get(target)const deps = depsMap.get(key)for (const dep of deps) {dep.run()}
}

回到 reactive 文件,将 track 和 trigger 写到对应的操作中。

src/reactivity/index.ts

// ...
export * from './effect'

src/reactivity/reactive.ts

import {target, trigger} from './index'export function reactive(obj) {return new Proxy(obj, {get(target, key) {track(target, key)return Reflect.get(target, key)},set(target, key, value) {const res = Reflect.set(target, key, value)trigger(target, key)return res},})
}

回到我们的单侧,将这几个库引入

src/reactivtiy/tests/effect.spec.ts

import {effect,reactive} from '../index' // ...

至此我们收集依赖和触发依赖的核心逻辑已经实现。我们现在可以跑 yarn test 进行检验。

结语

这篇文章是这个系列的开始,后续我会继续分享相关内容。慢慢完善我们对 vue3 的理解。
欢迎关注我,与我深入♂沟通。

这篇关于学Vue3核心概念与面试官斗智斗勇(一) 收集触发依赖的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/197735

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

每天认识几个maven依赖(ActiveMQ+activemq-jaxb+activesoap+activespace+adarwin)

八、ActiveMQ 1、是什么? ActiveMQ 是一个开源的消息中间件(Message Broker),由 Apache 软件基金会开发和维护。它实现了 Java 消息服务(Java Message Service, JMS)规范,并支持多种消息传递协议,包括 AMQP、MQTT 和 OpenWire 等。 2、有什么用? 可靠性:ActiveMQ 提供了消息持久性和事务支持,确保消

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo

深入理解数据库的 4NF:多值依赖与消除数据异常

在数据库设计中, "范式" 是一个常常被提到的重要概念。许多初学者在学习数据库设计时,经常听到第一范式(1NF)、第二范式(2NF)、第三范式(3NF)以及 BCNF(Boyce-Codd范式)。这些范式都旨在通过消除数据冗余和异常来优化数据库结构。然而,当我们谈到 4NF(第四范式)时,事情变得更加复杂。本文将带你深入了解 多值依赖 和 4NF,帮助你在数据库设计中消除更高级别的异常。 什么是

PostgreSQL核心功能特性与使用领域及场景分析

PostgreSQL有什么优点? 开源和免费 PostgreSQL是一个开源的数据库管理系统,可以免费使用和修改。这降低了企业的成本,并为开发者提供了一个活跃的社区和丰富的资源。 高度兼容 PostgreSQL支持多种操作系统(如Linux、Windows、macOS等)和编程语言(如C、C++、Java、Python、Ruby等),并提供了多种接口(如JDBC、ODBC、ADO.NET等