您当前的位置:首页 > 网站建设 > javascript
| php | asp | css | H5 | javascript | Mysql | Dreamweaver | Delphi | 网站维护 | 帝国cms | React | 考试系统 | ajax | jQuery | 小程序 |

详解Vue3的响应式原理解析

51自学网 2022-02-21 13:35:36
  javascript

Vue2响应式原理回顾

// 1.对象响应化:遍历每个key,定义getter、setter// 2.数组响应化:覆盖数组原型方法,额外增加通知逻辑const originalProto = Array.prototypeconst arrayProto = Object.create(originalProto)  ;['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort'].forEach(    method => {      arrayProto[method] = function () {        originalProto[method].apply(this, arguments)        notifyUpdate()      }    }  )function observe (obj) {  if (typeof obj !== 'object' || obj == null) {    return  }  // 增加数组类型判断,若是数组则覆盖其原型  if (Array.isArray(obj)) {    Object.setPrototypeOf(obj, arrayProto)  } else {    const keys = Object.keys(obj)    for (let i = 0; i < keys.length; i++) {      const key = keys[i]      defineReactive(obj, key, obj[key])    }  }}function defineReactive (obj, key, val) {  observe(val) // 解决嵌套对象问题  Object.defineProperty(obj, key, {    get () {      return val    },    set (newVal) {      if (newVal !== val) {        observe(newVal) // 新值是对象的情况        val = newVal        notifyUpdate()      }    }  })}function notifyUpdate () {  console.log('页面更新!')}

vue2响应式弊端:
响应化过程需要递归遍历,消耗较大
新加或删除属性无法监听
数组响应化需要额外实现
Map、Set、Class等无法响应式
修改语法有限制

Vue3响应式原理剖析

vue3使用ES6的Proxy特性来解决这些问题。

function reactive (obj) {  if (typeof obj !== 'object' && obj != null) {    return obj  }  // Proxy相当于在对象外层加拦截  // http://es6.ruanyifeng.com/#docs/proxy  const observed = new Proxy(obj, {    get (target, key, receiver) {      // Reflect用于执行对象默认操作,更规范、更友好      // Proxy和Object的方法Reflect都有对应      // http://es6.ruanyifeng.com/#docs/reflect      const res = Reflect.get(target, key, receiver)      console.log(`获取${key}:${res}`)      return res    },    set (target, key, value, receiver) {      const res = Reflect.set(target, key, value, receiver)      console.log(`设置${key}:${value}`)      return res    },    deleteProperty (target, key) {      const res = Reflect.deleteProperty(target, key)      console.log(`删除${key}:${res}`)      return res    }  })  return observed}//代码测试const state = reactive({  foo: 'foo',  bar: { a: 1 }})// 1.获取state.foo // ok// 2.设置已存在属性state.foo = 'fooooooo' // ok// 3.设置不存在属性state.dong = 'dong' // ok// 4.删除属性delete state.dong // ok

嵌套对象响应式

测试:嵌套对象不能响应

// 设置嵌套对象属性react.bar.a = 10 // no ok

添加对象类型递归

      // 提取帮助方法      const isObject = val => val !== null && typeof val === 'object'      function reactive (obj) {        //判断是否对象        if (!isObject(obj)) {          return obj        }        const observed = new Proxy(obj, {          get (target, key, receiver) {            // ...            // 如果是对象需要递归            return isObject(res) ? reactive(res) : res          },          //...        }

避免重复代理

重复代理,比如

reactive(data) // 已代理过的纯对象
reactive(react) // 代理对象

解决方式:将之前代理结果缓存,get时直接使用

const toProxy = new WeakMap() // 形如obj:observed      const toRaw = new WeakMap() // 形如observed:obj      function reactive (obj) {        //...        // 查找缓存,避免重复代理        if (toProxy.has(obj)) {          return toProxy.get(obj)        }        if (toRaw.has(obj)) {          return obj        }        const observed = new Proxy(...)        // 缓存代理结果        toProxy.set(obj, observed)        toRaw.set(observed, obj)        return observed      }      // 测试效果      console.log(reactive(data) === state)      console.log(reactive(state) === state)

总结

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


下载地址:
详解vue保存自动格式化换行
JavaScript中&nbsp;创建动态&nbsp;QML&nbsp;对象的方法
万事OK自学网:51自学网_软件自学网_CAD自学网自学excel、自学PS、自学CAD、自学C语言、自学css3实例,是一个通过网络自主学习工作技能的自学平台,网友喜欢的软件自学网站。