耀极客论坛

 找回密码
 立即注册
查看: 657|回复: 0

详解Vue3的响应式原理解析

[复制链接]

193

主题

176

帖子

276

积分

中级会员

Rank: 3Rank: 3

积分
276
发表于 2022-5-9 02:10:15 | 显示全部楼层 |阅读模式
  这篇文章主要为大家介绍了Vue3的响应式原理解析,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

Vue2响应式原理回顾
  1. // 1.对象响应化:遍历每个key,定义getter、setter
  2. // 2.数组响应化:覆盖数组原型方法,额外增加通知逻辑
  3. const originalProto = Array.prototype
  4. const arrayProto = Object.create(originalProto)
  5.   ;['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort'].forEach(
  6.     method => {
  7.       arrayProto[method] = function () {
  8.         originalProto[method].apply(this, arguments)
  9.         notifyUpdate()
  10.       }
  11.     }
  12.   )
  13. function observe (obj) {
  14.   if (typeof obj !== 'object' || obj == null) {
  15.     return
  16.   }
  17.   // 增加数组类型判断,若是数组则覆盖其原型
  18.   if (Array.isArray(obj)) {
  19.     Object.setPrototypeOf(obj, arrayProto)
  20.   } else {
  21.     const keys = Object.keys(obj)
  22.     for (let i = 0; i ‹ keys.length; i++) {
  23.       const key = keys[i]
  24.       defineReactive(obj, key, obj[key])
  25.     }
  26.   }
  27. }
  28. function defineReactive (obj, key, val) {
  29.   observe(val) // 解决嵌套对象问题
  30.   Object.defineProperty(obj, key, {
  31.     get () {
  32.       return val
  33.     },
  34.     set (newVal) {
  35.       if (newVal !== val) {
  36.         observe(newVal) // 新值是对象的情况
  37.         val = newVal
  38.         notifyUpdate()
  39.       }
  40.     }
  41.   })
  42. }
  43. function notifyUpdate () {
  44.   console.log('页面更新!')
  45. }
复制代码
  1. vue2响应式弊端:
  2. 响应化过程需要递归遍历,消耗较大
  3. 新加或删除属性无法监听
  4. 数组响应化需要额外实现
  5. Map、Set、Class等无法响应式
  6. 修改语法有限制
复制代码
Vue3响应式原理剖析
  vue3使用ES6的Proxy特性来解决这些问题。
  1. function reactive (obj) {
  2.   if (typeof obj !== 'object' && obj != null) {
  3.     return obj
  4.   }
  5.   // Proxy相当于在对象外层加拦截
  6.   // http://es6.ruanyifeng.com/#docs/proxy
  7.   const observed = new Proxy(obj, {
  8.     get (target, key, receiver) {
  9.       // Reflect用于执行对象默认操作,更规范、更友好
  10.       // Proxy和Object的方法Reflect都有对应
  11.       // http://es6.ruanyifeng.com/#docs/reflect
  12.       const res = Reflect.get(target, key, receiver)
  13.       console.log(`获取${key}:${res}`)
  14.       return res
  15.     },
  16.     set (target, key, value, receiver) {
  17.       const res = Reflect.set(target, key, value, receiver)
  18.       console.log(`设置${key}:${value}`)
  19.       return res
  20.     },
  21.     deleteProperty (target, key) {
  22.       const res = Reflect.deleteProperty(target, key)
  23.       console.log(`删除${key}:${res}`)
  24.       return res
  25.     }
  26.   })
  27.   return observed
  28. }
  29. //代码测试
  30. const state = reactive({
  31.   foo: 'foo',
  32.   bar: { a: 1 }
  33. })
  34. // 1.获取
  35. state.foo // ok
  36. // 2.设置已存在属性
  37. state.foo = 'fooooooo' // ok
  38. // 3.设置不存在属性
  39. state.dong = 'dong' // ok
  40. // 4.删除属性
  41. delete state.dong // ok
复制代码
嵌套对象响应式
  测试:嵌套对象不能响应
  1. // 设置嵌套对象属性
  2. react.bar.a = 10 // no ok
复制代码
  添加对象类型递归
  1.       // 提取帮助方法
  2.       const isObject = val => val !== null && typeof val === 'object'
  3.       function reactive (obj) {
  4.         //判断是否对象
  5.         if (!isObject(obj)) {
  6.           return obj
  7.         }
  8.         const observed = new Proxy(obj, {
  9.           get (target, key, receiver) {
  10.             // ...
  11.             // 如果是对象需要递归
  12.             return isObject(res) ? reactive(res) : res
  13.           },
  14.           //...
  15.         }
复制代码
避免重复代理
  重复代理,比如
  1. reactive(data) // 已代理过的纯对象
  2. reactive(react) // 代理对象
复制代码
  解决方式:将之前代理结果缓存,get时直接使用
  1. const toProxy = new WeakMap() // 形如obj:observed
  2.       const toRaw = new WeakMap() // 形如observed:obj
  3.       function reactive (obj) {
  4.         //...
  5.         // 查找缓存,避免重复代理
  6.         if (toProxy.has(obj)) {
  7.           return toProxy.get(obj)
  8.         }
  9.         if (toRaw.has(obj)) {
  10.           return obj
  11.         }
  12.         const observed = new Proxy(...)
  13.         // 缓存代理结果
  14.         toProxy.set(obj, observed)
  15.         toRaw.set(observed, obj)
  16.         return observed
  17.       }
  18.       // 测试效果
  19.       console.log(reactive(data) === state)
  20.       console.log(reactive(state) === state)
复制代码
总结

  本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|耀极客论坛 ( 粤ICP备2022052845号-2 )|网站地图

GMT+8, 2022-12-10 02:23 , Processed in 0.071867 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表