从头创建您自己的vue.js——第4部分(构建反应性)

从头创建您自己的vue.js——第4部分(构建反应性)
最新回答
不玩心枉少年

2024-02-01 21:24:45

核心答案:本文通过构建Dep依赖类和reactive函数,实现了Vue.js响应式系统的核心机制:依赖收集触发更新。关键步骤包括:

  1. Dep类:管理订阅者(subscribers),提供depend()(收集依赖)和notify()(触发更新)方法。
  2. reactive函数:将对象属性转换为响应式,通过Object.defineProperty拦截读写操作,与Dep实例关联。
  3. watchEffect:注册副作用函数,在依赖变化时自动执行。
1. 依赖类(Dep)的实现

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()遍历并执行所有订阅函数。

2. 响应式状态(reactive)的构建

将普通对象转换为响应式对象,核心是通过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()通知变更(仅在值实际变化时)。

3. 副作用注册(watchEffect)

注册副作用函数,并在依赖变化时自动执行:

let activeEffect = null;function watchEffect(fn) { activeEffect = fn; // 设置当前活动副作用 fn(); // 立即执行以收集依赖 activeEffect = null; // 重置}
  • 关键点

    通过activeEffect标记当前副作用函数,供Dep.depend()使用。

    首次执行fn()触发Getter,完成依赖收集。

4. 测试与验证

验证响应式系统是否正常工作:

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. 潜在问题与优化
  1. 嵌套对象:当前实现仅处理顶层属性,需递归转换嵌套对象(如reactive({ nested: { foo: 1 } }))。
  2. 数组支持:直接通过索引修改数组(如arr[0] = 1)无法触发更新,需重写数组方法(push/pop等)。
  3. 性能:Set存储订阅函数可能内存泄漏,需在组件卸载时清理(如Vue的effect.stop())。
总结

通过Dep类管理依赖、reactive函数转换对象、watchEffect注册副作用,实现了类似Vue 3的响应式系统。核心思想是:

  • 依赖收集:在Getter中记录当前副作用函数。
  • 触发更新:在Setter中通知所有订阅者重新执行。

此实现是Vue响应式原理的简化版,实际框架中还需处理更多边界情况(如删除属性、Map/Set支持等)。