Vue的响应式原理分析

2 篇文章 0 订阅

Vue 的响应式原理中 Object.defineProperty 有什么缺陷?为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty?

( 1.) Object.defineProperty无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应;
Object.defineProperty是可以监听数组下标变化的,对于javascript来讲,数组也是属于Object。

为什么Vue不劫持数组?

一、因为数组的位置不固定,数量多变,正常对象key对应value一般不会变,但是如果数组删除了某个元素,比如第一个元素被删除或者头部增加一个元素,那么将导致后面所有的key对应value错位,如果6个元素,也就会触发5次set。

二、数组元素可能非常非常多,每个元素进行劫持有一定浪费,这可能是Evan you对性能的考虑。

三、Vue将数组的7个变异方法进行了重写,也就是更改了Array原型上的方法达到劫持变化。

直接上代码测试:

const arr = [1, 2, 3, 4, 5, 6]

for (let key in arr) {
    let value = arr[key]
    Object.defineProperty(arr, key, {
        get() {
            console.log(`get: ${key}`)
            return value
        },
        set(newValue) {
            console.log(`set: ${key} to ${newValue}`)
            return value = newValue
        }
    })
}


arr[0] = 999 // 打印:set:0 to 999
arr[3] // 打印:get:3
arr.shift() // 会导致5次前移,所以产生5次get和5次set
/*
get: 1
set: 0 to 2
get: 2
set: 1 to 3
get: 3
set: 2 to 4
get: 4
set: 3 to 5
get: 5
set: 4 to 6
*/

( 2. ) Object.defineProperty只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历。Proxy可以劫持整个对象,并返回一个新的对象。
Proxy虽然是劫持的整个对象,但也是浅层劫持,属性值是对象时同样也需要深度遍历,不然该属性对象的变化也无法监测到。
测试:

const obj = {
    count: 5,
    user: { name: 'JavaScript', age: 22 }
}


const proxiedObj = new Proxy(obj, {
    get(target, key) {
        console.log(`get:${key}`)
        return target[key]
    },
    set(target, key, value) {
        console.log(`set:${key} to ${value}`)
        return target[key] = value
    }
})


proxiedObj.user.name = 'Golang'
/*
只会触发一次get user即:
get:user
*/

怎么深度劫持?也很简单,直接上代码:

function deepProxy(obj) {
    return new Proxy(obj, {
        get(target, key) {
            console.log(`get:${key}`)
            if (typeof target[key] === 'object' && target[key] !== null) {
                return deepProxy(target[key]) // 递归劫持
              }
              return target[key]
          },
          set(target, key, value) {
              console.log(`set:${key} to ${value}`)
              return target[key] = value
          }
      })
  
  
  }
  const obj = {
      count: 5,
      user: { name: 'JavaScript', age: 22 }
  }
  
  
  const proxiedObj = deepProxy(obj)
  proxiedObj.user.name = 'Golang'/*
  控制台如下:
  get:user
  set:name to Golang
  */

/* 修改/访问 原先不存在的属性 */ 
  console.log(proxiedObj.someProp) // get: someProp
  proxiedObj.someProp = 'some value' // set: someProp to some value

所以为什么proxy优于Object.defineProperty?

从以上的例子就能看到,Object.defineProperty必须“预先”劫持属性。被劫持的属性才会被监听到。所以后添加的属性,需要手动再次劫持。

而proxy代理了整个对象,不需要预先劫持属性,而是在获取/修改的时候,通过get/set方法来告诉你key。所以不管如何新增属性,总是能被捕获到。

Vue2和Vue3的响应式原理有所不同。 在Vue2中,响应式是通过Object.defineProperty来实现的。当一个对象被传入Vue的观察者系统中时,Vue会遍历对象的每个属性,并使用Object.defineProperty将它们转换为getter和setter。当属性被访问或修改时,Vue会通知相关的观察者进行更新。 而在Vue3中,响应式是通过Proxy对象来实现的。Proxy是ES6中的一个内置构造函数,可以拦截并代理对目标对象的操作。在Vue3中,当一个对象被传入Vue的观察者系统中时,Vue会使用Proxy对对象进行代理。当属性被访问或修改时,Proxy会拦截这些操作,并通知相关的观察者进行更新。 总结起来,Vue2使用Object.defineProperty来实现响应式,而Vue3使用Proxy来实现响应式。这两种实现方式都能实现相同的效果,但Vue3的Proxy机制更加灵活和高效,对于大型应用和性能要求较高的场景来说,Vue3的响应式系统更加优秀。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Vue2 和 Vue3响应式原理的区别](https://blog.csdn.net/qq_43835345/article/details/125378237)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [详细分析vue响应式原理](https://download.csdn.net/download/weixin_38752830/12925418)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [ruoyi-vue-pro yudao 项目报表设计器 积木报表模块启用及相关SQL脚本](https://download.csdn.net/download/zengwenbo225566/88234865)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值