2024-02-01 21:24:45
核心答案:本文通过构建Dep依赖类和reactive函数,实现了Vue.js响应式系统的核心机制:依赖收集与触发更新。关键步骤包括:
Dep类是响应式系统的基石,负责跟踪依赖并通知变更:
class Dep { subscribers = new Set(); // 存储订阅函数 // 收集当前活动的副作用函数 depend() { if (activeEffect) this.subscribers.add(activeEffect); } // 通知所有订阅者执行更新 notify() { this.subscribers.forEach(sub => sub()); }}subscribers使用Set避免重复订阅。
depend()依赖全局变量activeEffect(由watchEffect设置),将当前副作用函数加入订阅列表。
notify()遍历并执行所有订阅函数。
将普通对象转换为响应式对象,核心是通过Object.defineProperty拦截属性访问:
function reactive(obj) { Object.keys(obj).forEach(key => { const dep = new Dep(); // 每个属性独立依赖 let value = obj[key]; Object.defineProperty(obj, key, { get() { dep.depend(); // 收集依赖 return value; }, set(newValue) { if (newValue !== value) { value = newValue; dep.notify(); // 值变化时触发更新 } }, }); }); return obj;}每个属性关联独立的Dep实例,实现细粒度更新。
Getter中调用dep.depend()收集依赖。
Setter中调用dep.notify()通知变更(仅在值实际变化时)。
注册副作用函数,并在依赖变化时自动执行:
let activeEffect = null;function watchEffect(fn) { activeEffect = fn; // 设置当前活动副作用 fn(); // 立即执行以收集依赖 activeEffect = null; // 重置}通过activeEffect标记当前副作用函数,供Dep.depend()使用。
首次执行fn()触发Getter,完成依赖收集。
验证响应式系统是否正常工作:
const state = reactive({ count: 1, name: 'Marc' });watchEffect(() => { console.log('State changed:', state.count, state.name);});// 模拟异步更新setTimeout(() => state.count++, 1000);setTimeout(() => state.name = 'Johnny', 2000);预期输出:
State changed: 1 Marc // 初始执行State changed: 2 Marc // count更新State changed: 2 Johnny // name更新5. 潜在问题与优化通过Dep类管理依赖、reactive函数转换对象、watchEffect注册副作用,实现了类似Vue 3的响应式系统。核心思想是:
此实现是Vue响应式原理的简化版,实际框架中还需处理更多边界情况(如删除属性、Map/Set支持等)。