Vue3的数据响应式

283 阅读2分钟

这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战

一、Proxy取代defineProperty

先说说es6中的proxy:

let obj = new Proxy(target,handler);

这个里面的Proxy有两个对象:

  • target: 被代理对象
  • handler:是一个对象,声明代理target的某些操作
  • obj是被代理对象完成后返回的对象

Vue3中使用proxy提高了性能,打包后代码量也减少了很多,并且取代了Vue2中的definePeoperty的一些缺陷:属性的新增和删除无法实时监听,数组元素的新增和删除也无法监听。并且可以支持Map,set等,这就是Proxy增加了setset和delete的原因。

reactive

function reactive(target) {
    const handlers = collectionTypes.has(target.constructor)
        ? collectionHandlers
        : baseHandlers
    observed = new Proxy(target, handlers)
    return observed
}

这里主要是用来判断Proxy进入哪个方法,基本上除了set、map、weakset 和weakmap,都是走baseHandlers方法。

proxy

let data = [1,2,3]
let p = new Proxy(data, {
  get(target, key) {
    console.log('获取值:', key)
    return target[key]
  },
  set(target, key, value) {
    console.log('修改值:', key, value)
    target[key] = value
    return true
  }
})

p.push(4)

输出:

获取值: push
获取值: length
修改值: 3 4
修改值: length 4

Proxy的原理是在目标对象前设置一个拦截,当访问对象的时候,都必须经过这层拦截,也就是类似于代理,在外界访问对象的时候都可以实时进行过滤和更新对象。相对于defineproperty更厉害的地方就是数组和对象都可以直接触发getter和setter,但是数组会触发两次,因为获取push和修改length的时候也会触发。

Reflect

let data = [1,2,3]
let p = new Proxy(data, {
  get(target, key) {
    console.log('获取值:', key)
    return Reflect.get(target,key)
  },
  set(target, key, value) {
    console.log('修改值:', key, value)
    return Reflect.set(target,key, value)
  }
})

Reflect是一个内置对象,拥有一切javascript的操作方法,相对于Proxy负责对数组对象进行增删改查的监听操作,但是Vue3底层是通过Reflect获取对象的属性并进行增删改。也就是利用Proxy进行代理,再利用Relfect进行反射回应,最终和Proxy功能一一对应,更函数式标准化。