看一下具体使用效果:
const obj1 = { name: 'curry', age: 30 }const obj2 = { weight: '130', height: '180' }const obj1Proxy = reactive(obj1)const obj2Proxy = reactive(obj2)watchFn(function() {console.log('我依赖了obj1的name属性')console.log(obj1Proxy.name)})watchFn(function() {console.log('我依赖了age属性')console.log(obj1Proxy.age)})watchFn(function() {console.log('我依赖了obj2的weight属性')console.log(obj2Proxy.weight)})watchFn(function() {console.log('我依赖了obj2的height属性')console.log(obj2Proxy.height)})console.log('----------以上为初始化执行 , 以下为修改后执行-------------')obj1Proxy.name = 'kobe'obj1Proxy.age = 24obj2Proxy.weight = 100obj2Proxy.height = 165

文章插图
5.10.总结整理
通过上面9步完成了最终响应式原理的实现 , 下面对其进行整理一下:
- watchFn函数:传入该函数的函数都是需要被收集为响应式函数的 , 对响应式函数进行初始化调用 , 使Proxy的get捕获器能捕获到属性访问;
- function watchFn(fn) { currentReactiveFn = fn // 先调用一次函数 , 提醒Proxy的get捕获器需要收集响应式函数了 fn() // 收集完成将currentReactiveFn重置 currentReactiveFn = null }
- Depend类:reactiveFns用于存放响应式函数 , addDependFn方法实现对响应式函数的收集 , notify方法实现当属性值变化时 , 去调用对应的响应式函数;
- // 将currentReactiveFn放到Depend之前 , 方便其拿到 let currentReactiveFn = null class Depend { constructor() { // 用于存放响应式函数 this.reactiveFns = new Set() } // 用户添加响应式函数 addDependFn() { // 先判断一下currentReactiveFn是否有值 if (currentReactiveFn) { this.reactiveFns.add(currentReactiveFn) } } // 用于执行响应式函数 notify() { this.reactiveFns.forEach(fn => { fn() }) } }
- reactive函数:实现将普通对象转成代理对象 , 从而将其转变为可响应式对象;
- function reactive(obj) { return new Proxy(obj, { get: function(target, key, receiver) { const dep = getDepend(target, key) // 直接调用addDepend方法 , 让它去收集 dep.addDependFn() return Reflect.get(target, key, receiver) }, set: function(target, key, newValue, receiver) { Reflect.set(target, key, newValue, receiver) // 根据当前对象target和设置的key , 去获取对应的dep const dep = getDepend(target, key) // 当set捕获器捕获到属性变化时 , 自动去调用notify dep.notify() } }) }
- getDepend函数:根据指定的对象和对象属性(key)去查找对应的dep对象;
- // 1.创建一个WeakMap存储结构 , 存放对象 const objWeakMap = new WeakMap() // 2.封装一个获取dep的函数 function getDepend(obj, key) { // 2.1.根据对象 , 获取对应的map let map = objWeakMap.get(obj) // 如果是第一次获取这个map , 那么需要先创建一个map if (!map) { map = new Map() // 将map存到objWeakMap中对应key上 objWeakMap.set(obj, map) } // 2.2.根据对象的属性 , 获取对应的dep let dep = map.get(key) // 如果是第一次获取这个dep , 那么需要先创建一个dep if (!dep) { dep = new Depend() // 将dep存到map中对应的key上 map.set(key, dep) } // 2.3最终将dep返回出去 return dep }
6.Vue2响应式原理的实现
Vue3响应式原理已经实现了 , 那么Vue2只需要将Proxy换成Object.defineProperty就可以了 。
- 将reactive函数改一下即可;
function reactive(obj) {// 1.拿到obj所有的keyconst keys = Object.keys(obj)// 2.遍历所有的keys , 添加存取属性描述符keys.forEach(key => {let value = https://www.isolves.com/it/cxkf/yy/js/2022-03-30/obj[key]Object.defineProperty(obj, key, {get: function() {const dep = getDepend(obj, key)// 直接调用addDepend方法 , 让它去收集dep.addDependFn()return value},set: function(newValue) {value = newValue// 根据当前对象设置的key , 去获取对应的depconst dep = getDepend(obj, key)// 监听到属性变化时 , 自动去调用notifydep.notify()}})})// 3.将obj返回return obj}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 您与这个网站的连接不安全?教你用python轻松解决
- 带状疱疹饮食注意什么
- 给你一个团队,你该怎么带?做好这五点,团队大变样!
- 春天到了,30种野菜辨别图片,带你认识不同的野菜和吃法
- 红烧带鱼烧豆腐的做法
- 吃野菜,带你进入健康地带
- 无神之界|我拼尽全力考上的二本,难道带给我的只能是耻辱吗?女研究生痛哭中发出灵魂之问
- 韩国|开放的“韩国”现状,带你看看真实的韩国
- 黄瓜|恩克减肥34天后回归,体重不降反增加,网友:安全带尽力了
- 大一新生入学必备清单 上大学要带什么东西
