详解Vue3的响应式原理解析

发布时间:2022-04-16 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了详解Vue3的响应式原理解析脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

Vue2响应式原理回顾

// 1.对象响应化:遍历每个key,定义getter、setter
// 2.数组响应化:覆盖数组原型方法,额外增加通知逻辑
const originalPRoto = Array.prototyPE
const 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 &amp;& 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)

总结

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

脚本宝典总结

以上是脚本宝典为你收集整理的详解Vue3的响应式原理解析全部内容,希望文章能够帮你解决详解Vue3的响应式原理解析所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签:Vue3的