5.4.自动监听对象的变化
在修改对象属性值后 , 还是需要手动去调用其notify函数来通知响应式函数执行 , 其实可以做到自动监听对象属性的变化 , 来自动调用notify函数 , 这个想必就很容易了 , 在前面做了那么多功课 , 就是为了这里 , 不管是用Object.defineProperty还是Proxy都可以实现对象的监听 , 这里我使用功能更加强大的Proxy , 并结合Reflect来实现 。
class Depend {constructor() {// 用于存放响应式函数this.reactiveFns = []}// 用户添加响应式函数addDependFn(fn) {this.reactiveFns.push(fn)}// 用于执行响应式函数notify() {this.reactiveFns.forEach(fn => {fn()})}}const obj = {name: 'curry',age: 30}const dep = new Depend()// 在watchFn中使用dep的addDependFn来收集function watchFn(fn) {dep.addDependFn(fn)}// 创建一个Proxyconst objProxy = new Proxy(obj, {get: function(target, key, receiver) {return Reflect.get(target, key, receiver)},set: function(target, key, newValue, receiver) {Reflect.set(target, key, newValue, receiver)// 当set捕获器捕获到属性变化时 , 自动去调用notifydep.notify()}})watchFn(function() {let newName = objProxy.nameconsole.log(newName)console.log('1:' + objProxy.name)})watchFn(function() {console.log('2:' + objProxy.name)})objProxy.name = 'kobe'objProxy.name = 'klay'objProxy.name = 'james'注意:后面使用到的obj对象 , 需都换成代理对象objProxy , 这样储能监听到属性值是否被设置了 。打印结果:name属性修改了三次 , 对应依赖函数就执行了三次 。

文章插图
5.5.对象依赖的管理(数据存储结构设计)
在上面实现响应式过程中 , 都是基于一个对象的一个属性 , 如果有多个对象 , 这多个对象中有不同或者相同的属性呢?我们应该这样去单独管理不同对象中每个属性所对应的依赖呢?应该要做到当某一个对象中的某一个属性发生变化时 , 只去执行对这个对象中这个属性有依赖的函数 , 下面就来讲一下怎样进行数据存储 , 能够达到我们的期望 。在ES16中 , 给我们新提供了两个新特性 , 分别是Map和WeakMap , 这两个类都可以用于存放数据 , 类似于对象 , 存放的是键值对 , 但是Map和WeakMap的key可以存放对象 , 而且WeakMap对对象的引用是弱引用 。如果对这两个类不太熟悉 , 可以去看看上一篇文章:ES6-ES12简单知识点总结
- 将不同的对象存放到WeakMap中作为key , 其value存放对应的Map;
- Map中存放对应对象的属性作为key , 其value存放对应的依赖对象;
- 依赖对象中存放有该属性对应响应式函数数组;
const obj1 = { name: 'curry', age: 30 }const obj2 = { name: 'kobe', age: 24 }
文章插图
5.6.对象依赖管理的实现
已经确定了怎么存储了 , 下面就来实现一下吧 。
- 封装一个getDepend函数 , 主要用于根据对象和key , 来找到对应的dep;
- 如果没有找到就先进行创建存储;
// 1.创建一个WeakMap存储结构 , 存放对象const objWeakMap = new WeakMap()// 2.封装一个获取dep的函数function getDepend(obj, key) {// 2.1.根据对象 , 获取对应的maplet map = objWeakMap.get(obj)// 如果是第一次获取这个map , 那么需要先创建一个mapif (!map) {map = new Map()// 将map存到objWeakMap中对应key上objWeakMap.set(obj, map)}// 2.2.根据对象的属性 , 获取对应的deplet dep = map.get(key)// 如果是第一次获取这个dep , 那么需要先创建一个depif (!dep) {dep = new Depend()// 将dep存到map中对应的key上map.set(key, dep)}// 2.3最终将dep返回出去return dep}在Proxy的捕获器中获取对应的dep:// 创建一个Proxyconst objProxy = new Proxy(obj, {get: function(target, key, receiver) {return Reflect.get(target, key, receiver)},set: function(target, key, newValue, receiver) {Reflect.set(target, key, newValue, receiver)// 根据当前对象target和设置的key , 去获取对应的depconst dep = getDepend(target, key)console.log(dep)// 当set捕获器捕获到属性变化时 , 自动去调用notifydep.notify()}})
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 您与这个网站的连接不安全?教你用python轻松解决
- 带状疱疹饮食注意什么
- 给你一个团队,你该怎么带?做好这五点,团队大变样!
- 春天到了,30种野菜辨别图片,带你认识不同的野菜和吃法
- 红烧带鱼烧豆腐的做法
- 吃野菜,带你进入健康地带
- 无神之界|我拼尽全力考上的二本,难道带给我的只能是耻辱吗?女研究生痛哭中发出灵魂之问
- 韩国|开放的“韩国”现状,带你看看真实的韩国
- 黄瓜|恩克减肥34天后回归,体重不降反增加,网友:安全带尽力了
- 大一新生入学必备清单 上大学要带什么东西
