Vue3 之手写实现 shallowReactive(拦截功能)

916 阅读2分钟

vue3 中的响应式原理的核心是通过 Proxy(代理),拦截对目标对象的任意属性的任意操作,诸如增删改查等,有 13 种。new Proxy() 传入两个参数,第一个是要代理的目标对象 target,第二个是 handler 对象,其属性就是对应的 13 个函数,用于定义在执行各种操作时,new 出来的这个 Proxy 对象的行为。 下面我们自己手写实现一个 shallowReactive,主要是拦截功能的这部分:

function shallowReactive(target) {
  if (target && typeof target === 'object') {
    return new Proxy(target, handler)
  } else {
    return target
  }
}

注意:if 的判断里之所以要加上 target &&,是因为用 typeof 遇到 null 得到的结果也是 object

handler 对象

const handler = {
  get(target, prop) {
    console.log('读取')
    return Reflect.get(target, prop)
  },
  set(target, prop, value) {
    console.log('修改')
    return Reflect.set(target, prop, value)
  },
  deleteProperty(target, prop) {
    console.log('删除')
    return Reflect.deleteProperty(target, prop)
  }
}

我们可以新建一个普通对象 obj 进行测试:

const obj = {
  name: 'Jay',
  newAlbum: {
    time: '很快'
  }
}

obj 传给我们自己定义的 shallowReactive,将返回值赋给 proxyObj,然后对其进行了 += 的操作,也就是进行了“查”和“改”:

const proxyObj = shallowReactive(obj)
proxyObj.name += 'Chou' 

现在打印代理对象 console.log(proxyObj) 得到结果如下:

image.png

打印目标对象 console.log(obj)

image.png

可以看到代理对象和目标对象的 name 都被修改了,且打印出了“读取”和“修改”,证明 handler 对象里的 getset 触发。

注意:如果在 setget 函数里不调用 Reflect 的相关属性函数,比如我们把 return Reflect.get(target, prop)return Reflect.set(target, prop, value) 都进行注释,那么打印结果如下:

image.png

可以看到代理对象和目标对象的 name 属性都没有被更改。

如果只注释 return Reflect.get(target, prop),结果如下:

image.png

因为不返回 Reflect.get 导致 proxyObj.nameundefined

所以 handler 对象的每个属性(函数)里都需要返回相应的 Reflect 的属性(函数)。Reflect 是一个内置的对象,提供拦截 js 操作的方法。注意 Reflect 不是一个函数对象,不可构造,意味着它的所有方法都是静态方法。这些方法与 Proxy 的 handler 的方法一一对应,也是 13 种。总结一句话就是使用 Proxy 实现对对象内部数据的劫持,使用 Reflect 操作对象内部数据。

本篇到此结束,vue3 的更多知识我也正在学习中,不足之处还望各位大佬不吝斧正~

感谢.gif

点赞.png