Vue3 源码阅读(3)- ProxyHandlers
在上一节 reactive 的源码中,我们发现其向 createReactiveObject 函数传入了两个 handler:
1234567return createReactiveObject( target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
这两个 handler 都是 ProxyHandler 类型,会根据上一节解释过的 TargetType 传给 Proxy 构造函数作为第三个实参:
1234const proxy = new Proxy( target, targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers);
mutableHandlers 和 mutableCollectionHandlers 分别为 baseHandlers.ts,collectionHandlers.ts 暴露的主要监听器
baseHandlers该文件中的 handler 用于处理 Objec ...
Vue3 源码阅读(2)- reactive
首先我们来看 packages/reactivity/reactive.ts 是如何创建响应式对象的
reactive对外暴露的最常用的接口
12345678910111213export function reactive(target: object) { // if trying to observe a readonly proxy, return the readonly version. if (isReadonly(target)) { return target; } return createReactiveObject( target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap );}
最表层的逻辑很简单,判断是否为只读对象
是则返回其本身
否则创建一个响应式对象返回
createReactiveObject 是创建响应式对象的工厂方法,是该文件的核心
createReactiveObject接着 ...
Vue3 源码阅读(1)- 前置知识
文章是边看源码边写的,建议看文章的同时看源码(不然会看不懂)
知识储备阅读后文需要以下知识储备:
ESNEXT 最新规范
理解 vue2 文档中编写的响应式原理
pnpm 和其 workspace 的使用,了解 pnpm link 指令
本人开发环境
操作系统:Windows11 x64 专业版
IDE:vscode 最新稳定版
调试项目 package.json 依赖版本
12345678910111213{ "dependencies": { "vue": "^3.2.37" }, "devDependencies": { "@vitejs/plugin-vue": "^2.3.3", "@vitejs/plugin-vue-jsx": "^1.3.10", "sass": "^1.53.0", ...
打包插件
本文参考了:超硬核|带你畅游在 Webpack 插件开发者的世界
需求
需要把打包的所有产物压缩到一个 zip 文件中
可以定义文件名
思路
需要找到能获取生成完毕后的文件资源的钩子
遍历所有文件,使用第三方库压缩文件,我们这边使用 jszip
实现
查阅文档可知 emit 为在文件输出前的钩子,该钩子为异步串行钩子,其回调参数为 compilation 对象
compilation 对象能通过 getAssets 函数获得所有的资源数组
我们通过 typescript 类型声明文件发现,asset 对象结构如下
其中的 source 对象结构如下
其中的 source 函数就是我们所需要的
继续查阅文档得知 compilation.emitAsset 方法可以增加输出的文件
其第二个参数 source 对象需要通过 webpack-source 这个库来创建
最后实现的完整代码如下:
123456789101112131415161718192021222324252627282930313233343536373839404142import JSZi ...
前置知识
TapableTapable 是一个事件发布订阅库,提供了各种同步、异步的事件订阅发布方法
webpack 通过 Tapable 暴露了大量的事件给插件开发者注册,开发者通过这些事件来介入编译打包的过程
学习 Tapable 看这篇文章,写的很好
webpack 插件机制webpack 暴露了非常非常多的 hook 供开发者注册,他们存在于不同的对象上,不同对象的钩子分工明确,涵盖了编译、资源文件等各种场景
看这篇文章,了解插件的开发方式、其大致结构和较常用的几个钩子对象
webpack 钩子文档
compiler(常用)
compilation(常用)
parser(需要处理源码时常用)
resolver
哈希表
简述哈希的基本原理是将给定的键值转换为偏移地址来检索记录
键转换为地址是通过一种关系(公式)来完成的,这就是哈希(散列)函数
缺点虽然哈希表是一种有效的搜索技术,但是它还有些缺点
两个不同的关键字,由于哈希函数值相同,因而被映射到同一表位置上。该现象称为冲突
发生冲突的两个关键字称为该哈希函数的同义词
如何设计哈希函数以及如何避免冲突就是哈希表的常见问题,好的哈希函数的选择有两条标准:
简单并且能够快速计算
能够在址空间中获取键的均匀分布
应用应用到哈希表的经典题目:两数之和
滑动窗口的最大值
题目给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口 k 内的数字。滑动窗口每次只向右移动一位。返回滑动窗口最大值
1234567891011输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3输出: [3,3,5,5,6,7]解释: 滑动窗口的位置 最大值--------------- -----[1 3 -1] -3 5 3 6 7 3 1 [3 -1 -3] 5 3 6 7 3 1 3 [-1 -3 5] 3 6 7 5 1 3 -1 [-3 5 3] 6 7 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7] 7
思路使用一个双端队列(队列两面都可进出),用于存储处于窗口中的值的下标,保证窗口头部元素永远是窗口最大值
当前进入的元素下标 - 窗口头部元素的下标 & ...
栈的压入、弹出序列
问题输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序
假设压入栈的所有数字均不相等
例如序列 1,2,3,4,5 是某栈的压入顺序,序列 4,5,3,2,1 是该压栈序列对应的一个弹出序列,但 4,3,5,1,2 就不可能是该压栈序列的弹出序列(注意:这两个序列的长度是相等的)
思路用一个栈来模拟压入、弹出的过程即可:
使用一个指针指向弹出序列的头部
根据压入序列入栈
入栈时判断入栈元素是否跟弹出序列指针元素相同
若相同,则指针向后移,数据出栈
重复执行 1,2,3,4 直到所有元素都入栈完成,如果出栈顺序正确,此时栈为空
实现1234567891011121314151617function IsPopOrder(pushArr, popArr) { if (!pushArr || !popArr || pushArr.length == 0 || popArr.length == 0) { return; } let stack = []; let index = 0; // 入栈 ...
使用栈实现队列
思路队列和栈的区别就是弹出顺序,我们只需要把反转出栈顺序即可
那么需要维护两个栈,一个栈用来入列,一个栈来反转元素顺序并出列:
入列栈(栈1)
推入队列的数据都丢到这
出列栈(栈2)
弹出时从这个栈弹出,如果没有数据,则把入列栈的所有数据弹出并压入,然后再弹出以反转顺序
实现1234567891011121314151617181920212223242526function queue() { this.pushStack = []; this.popStack = [];}queue.prototype = { push: function (item) { this.pushStack.push(item); }, pop: function () { if (this.popStack.length === 0) { while (this.pushStack.length) { this.popStack.push(this.pushStac ...
栈和队列
栈和队列属于线性结构,他们之间值的取出操作有区别
栈先进后出
用数组来模拟:
123456789101112131415function stack(arr = []) { this.value = arr.slice();}stack.prototype = { add: function (item) { this.value.push(item); }, pop: function () { return this.value.pop(); },};const s = new stack([1, 2, 3]);s.add(4); // [1, 2, 3, 4]s.pop(); // 4 -> [1, 2, 3]
队列先进先出
用数组来模拟:
123456789101112131415function queues(arr = []) { this.value = arr.slice();}queues.prototype = { ad ...