第 8 卷
13const effectFn = () => {
| 14 | //执行副作用函数前,清除该函数在所有依赖中的记录(避免重复收集) |
|---|---|
| 15 | cleanup(effectFn); |
| 16 | activeEffect = effectFn; //标记当前活跃的副作用函数 |
| 17 | fn(); //执行副作用函数,触发Proxy的get拦截,进行依赖收集 |
| 18 | activeEffect = null; //收集完成后清空标记 |
| 19 | }; |
| 20 | //初始化执行一次副作用函数 |
| 21 | effectFn(); |
| 22 } |
23 24/**
25* 清除副作用函数的依赖记录
| 26 | * @param {Function} effectFn -要清除的副作用函数 |
|---|---|
| 27 | */ |
| 28 | function cleanup(effectFn) { |
| 29 | //遍历targetMap,找到所有包含当前effectFn的依赖集合并删除 |
| 30 | for (const [target, keyMap] of targetMap) { |
| 31 | for (const [key, effects] of keyMap) { |
| 32 | effects.delete(effectFn); |
| 33 | } |
| 34 | } |
| 35 | } |
36 37/**
38* 依赖收集:在响应式数据被访问时调用 39* @param {Object} target - 目标对象
| 40 | * @param {string|symbol} key -被访问的属性名 |
|---|---|
| 41 | */ |
| 42 | function track(target, key) { |
| 43 | //若没有活跃的副作用函数,无需收集依赖 |
| 44 | if (!activeEffect) return; |
45
| 46 | // 1.从targetMap中获取目标对象对应的keyMap(属性-副作用映射) |
|---|---|
| 47 | let keyMap = targetMap.get(target); |
| 48 | if (!keyMap) { |
| 49 | targetMap.set(target, (keyMap = new Map())); |
| 50 | } |
| 52 | // 2.从keyMap中获取属性对应的副作用集合 |
| 53 | let effects = keyMap.get(key); |
| 54 | if (!effects) { |
60} 61
62/** 63* 触发更新:在响应式数据被修改时调用
64* @param {Object} target - 目标对象
| 65 | * @param {string|symbol} key -被修改的属性名 |
|---|---|
| 66 | */ |
| 67 | function trigger(target, key) { |
| 68 | // 1.从targetMap中获取目标对象对应的keyMap |
| 69 | const keyMap = targetMap.get(target); |
| 70 | if (!keyMap) return; |
71 72// 2. 获取属性对应的副作用集合
73const effects = keyMap.get(key);
74if (!effects) return;
75
| 76 | // 3.执行所有副作用函数(创建新数组避免遍历中删除元素导致的问题) |
|---|---|
| 77 | [...effects].forEach(effectFn => effectFn()); |
| 78 | } |
79 80/**
81* 创建响应式对象(核心:Proxy代理)
| 82 | * @param {Object} target -要代理的目标对象 |
|---|---|
| 83 | * @returns {Proxy}响应式代理对象 |
| 84 | */ |
| 85 | function reactive(target) { |
| 86 | //校验:只代理对象/数组(基本类型无需代理) |
| 87 | if (target === null || typeof target !== 'object') { |
| 88 | return target; |
补充总结(新增3道面试题)
- 事件总线(EventBus):基于发布-订阅模式,核心是维护事件注册表,提供on/emit/off/once方
法,实现组件解耦通信
- 函数柯里化(curry):将多参数函数转化为单参数函数序列,通过闭包保存已接收参数,参数足够
时执行原函数,支持分步传参和this绑定
- Vue3响应式:核心是Proxy代理+Reflect操作,配合effect/track/trigger实现依赖收集和更新触
发,解决了Vue2的数组/新增属性响应式缺陷,依赖存储用WeakMap避免内存泄漏
(注:文档部分内容可能由 AI 生成)