Vue响应式原理三:响应式依赖收集-类

发布于:2025-07-13 ⋅ 阅读:(17) ⋅ 点赞:(0)

前提:实际开发中,响应式对象肯定是不止一个对象的, 使用数组reactiveFns, 所有依赖的函数都放到数组里面,是满足不了多个响应式对象,使用类单独来管理一个对象所有的依赖

1. 响应式依赖收集-类

  • 1.1. 类结构:创建Depend类来管理响应式依赖,包含reactiveFns数组存储依赖函数
  • 1.2. 核心方法:
  • addDepend(fn):添加依赖函数到数组,会先判断fn是否存在
  • notify():遍历执行所有收集的依赖函数
  • 代码如下:
	// 使用类单独来管理一个对象所有的依赖
	class Depend {
	  constructor() {
	    this.reactiveFns = [];
	  }
	
	  addDepend (fn) {
	    if(fn) {
	     	// 将依赖函数添加到数组,
	      this.reactiveFns.push(fn);
	    }
	  }
	
	  notify () {
	    this.reactiveFns.forEach(fn => {
	    	// 遍历执行所有收集的依赖函数
	      fn()
	    })
	  }
	}

  • 1.3. 优势: 相比单一数组管理,可以针对不同对象创建独立的Depend实例,避免所有依赖混在一起
  • 1.4. 执行过程
    • 创建Depend实例:const dep = new Depend()
    • 收集依赖:通过watchFn函数调用dep.addDepend(fn)
    • 触发更新:修改属性后手动调用dep.notify()
    • 示例代码如下:
    	// 创建Depend实例
    	const dep = new Depend()
    	function watchFn (fn) {
    	  dep.addDepend(fn)
    	  // 传入函数后立即执行一次,类似watchEffect()
    	  fn()
    	}
    	// 响应式函数
    	watchFn(function foo () {
    	  console.log('foo: ', obj.name);
    	  console.log('foo: ', obj.age);
    	  console.log('foo function');
    	})
    	
    	watchFn(function bar () {
    	  console.log('bar: ', obj.name + ' hello');
    	  console.log('bar: ', obj.age + 10);
    	  console.log('bar function');
    	})
    	// 修改obj的属性
    	obj.name = 'kobe'
    
    	// 当依赖发生变化时,会执行对应的响应式函数
    	dep.notify()
    	```
    
  • 1.5. 当前问题:
  • 每次属性修改后需要手动调用dep.notify()
  • 容易遗漏导致依赖不更新
  • 多个属性变更时需要多次调用
	// 参考上面的代码...
	
	// 修改obj的属性
	console.log('name发生变化时----------------------------------------');
	obj.name = 'kobe'
	// 当依赖发生变化时,会执行对应的响应式函数
	dep.notify()
	
	// 再次修改obj的属性
	obj.name = 'james'
	// 每次手动通知,一旦忘记就不是响应式了
	// dep.notify()
    1. 完整代码如下:
       	// 使用类单独来管理一个对象所有的依赖
       class Depend {
         constructor() {
          
           this.reactiveFns = [];
         }
       
         addDepend (fn) {
           if(fn) {
             // 将依赖函数添加到数组,
             this.reactiveFns.push(fn);
           }
         }
       
         notify () {
           this.reactiveFns.forEach(fn => {
             // 遍历执行所有收集的依赖函数
             fn()
           })
         }
       }
       
       // 实际开发中,响应式对象肯定是不止一个对象的
       // 例如: 
       // const user = { nickName: 'kobe', level: 100 }
       // const product = { name: '电脑', price: 1000 }
       // 有一个弊端,只有一个数组reactiveFns, 所有依赖的函数都放到数组里面,是满足不了多个响应式对象
       // 例如:一旦修改了product.name所有的响应式函数都会执行,目标是只想要执行product.name的响应式函数
       
       const obj = {
         name: 'why',
         age: 18
       }
       
       
       // 当上面有很多依赖函数时,很难收集
       // 设置一个专门执行响应式函数的一个函数
       const dep = new Depend()
       // obj => new Depend()
       // user => new Depend()
       // product => new Depend()
       function watchFn (fn) {
         dep.addDepend(fn)
         // 传入函数后立即执行一次,类似watchEffect()
         fn()
       }
       
       watchFn(function foo () {
         console.log('foo: ', obj.name);
         console.log('foo: ', obj.age);
         console.log('foo function');
       })
       
       watchFn(function bar () {
         console.log('bar: ', obj.name + ' hello');
         console.log('bar: ', obj.age + 10);
         console.log('bar function');
       })
       
       
       
       // 修改obj的属性
       console.log('name发生变化时----------------------------------------');
       obj.name = 'kobe'
       
       // 当依赖发生变化时,会执行对应的响应式函数
       dep.notify()
       
       // 修改obj的属性
       console.log('age发生变化时----------------------------------------');
       obj.age = 20
       dep.notify()
       
       console.log('name发生变化时----------------------------------------');
       obj.name = 'james'
       // 每次手动通知,一旦忘记就不是响应式了
       // dep.notify()
       ```
    
  • 1.7. 后续改进:
  • 将展示如何自动创建依赖收集器
  • 实现属性变更自动通知机制

网站公告

今日签到

点亮在社区的每一天
去签到