第 7 卷
75this.off(eventName, onceCallback);
76};
77// 订阅包装后的回调 78this.on(eventName, onceCallback);
79} 80}
81 82// 测试示例
83const eventBus = new EventBus();
84 85// 1. 普通订阅与发布
86function handleTest(arg1, arg2) { 87console.log('普通事件触发:', arg1, arg2);
88}
十二、手写函数柯里化(curry)的代码实现
核心原理
- 柯里化是将接收多个参数的函数,转化为接收单一参数(或部分参数)的函数序列的过程,最终返
回接收剩余参数并执行原函数的函数
- 核心逻辑:保存已接收的参数,判断已接收参数数量是否达到原函数的参数长度(形参长度),若
达到则执行原函数,否则返回一个新函数继续接收参数
- 支持特性:
- 自动判断参数是否足够,足够则执行
- 支持分步传递参数,也支持一次性传递所有参数
- 兼容原函数的this指向
- 依赖原函数的 length 属性获取形参数量,若原函数是剩余参数(...rest)形式,需手动指定参数
长度
实现代码
Code block
1/** 2* 函数柯里化
3* @param {Function} fn - 待柯里化的原函数 4* @param {number} [arity=fn.length] - 原函数的参数长度(若原函数用rest参数,需手动
指定)
5* @returns {Function} 柯里化后的函数
11} 12
13// 递归生成柯里化函数,接收已传递的参数(闭包保存)
14const curried = function(...args) {
| 15 | const _this = this; //保存当前this指向(用于原函数执行时绑定) |
|---|---|
| 16 | //情况1:已传递的参数数量>=原函数参数长度,执行原函数 |
| 17 | if (args.length >= arity) { |
| 18 | return fn.apply(_this, args); |
| 19 | } |
| 20 | //情况2:参数不足,返回新函数继续接收参数 |
| 21 | return function(...nextArgs) { |
| 22 | //合并已接收的参数和新传递的参数,递归调用curried |
| 23 | return curried.apply(_this, [...args, ...nextArgs]); |
| 24 | }; |
| 25 | }; |
26 27return curried;
28} 29
30// 测试示例 31// 1. 普通函数柯里化
32function add(a, b, c) { 33return a + b + c;
34} 35const curriedAdd = curry(add);
36 37// 分步传递参数
| 38 | console.log(curriedAdd(1)(2)(3)); // 6 |
|---|---|
| 39 | console.log(curriedAdd(1, 2)(3)); // 6 |
| 40 | console.log(curriedAdd(1)(2, 3)); // 6 |
41 42// 一次性传递所有参数
43console.log(curriedAdd(1, 2, 3)); // 6 44
45// 2. 绑定this的柯里化函数 46const obj = {
47name: '柯里化', 48sayHello: function(greet, msg) {
49return `${greet},${this.name}:${msg}`;
51};
52const curriedSayHello = curry(obj.sayHello);
| 56 | // 3.处理rest参数函数(需手动指定参数长度) |
|---|---|
| 57 | function sum(...args) { |
| 58 | return args.reduce((total, curr) => total + curr, 0); |
| 59 | } |
| 60 | //手动指定需要接收3个参数 |
| 61 | const curriedSum = curry(sum, 3); |
| 62 | console.log(curriedSum(1)(2)(3)); // 6 |
| 63 | console.log(curriedSum(1, 2)(3)); // 6 |
64
十三、手写Vue3响应式原理的代码实现(简易版)
核心原理(Vue3 vs Vue2)
- Vue3 响应式核心从 Vue2 的 Object.defineProperty 改为Proxy,解决了 Vue2 的缺陷:
- 支持数组索引/长度变化的响应式
- 支持新增/删除对象属性的响应式
- 无需递归劫持初始对象的所有属性(Proxy 是懒代理,访问属性时才触发劫持)
- 核心模块:
- Proxy:代理目标对象,拦截属性的读取(get)和设置(set)操作
- Reflect:配合 Proxy 操作目标对象,确保操作的正确性和规范性
- effect:副作用函数(如组件渲染函数),依赖收集时记录该函数,数据变化时重新执行
- track:依赖收集,在 Proxy 的 get 拦截中调用,记录“目标对象-属性-副作用函数”的映射关系
- trigger:触发更新,在 Proxy 的 set 拦截中调用,找到对应属性的所有副作用函数并执行
- 依赖存储:用 WeakMap(目标对象 -> Map(属性名 -> Set(副作用函数)))的结构,避免内存
泄漏
实现代码
Code block
1// 1. 存储依赖的结构:WeakMap<target, Map<key, Set<effect>>> 2const targetMap = new WeakMap();
3
| 4 | // 2.当前活跃的副作用函数(依赖收集时需要记录) |
|---|---|
| 5 | let activeEffect = null; |
| 7 | /** |