reactive的实现过程--版本3.2.45

reactive 是 vue3 中对数据进行劫持的核心,主要是利用了 Proxy 进行劫持。

Proxy 本质上是对某个对象的劫持,这样它不仅仅可以监听对象某个属性值的变化,还可以监听对象属性的新增和删除;而 Object.defineProperty 是给对象的某个已存在的属性添加对应的 gettersetter,所以它只能监听这个属性值的变化,而不能去监听对象属性的新增和删除。

reactive.ts文件

官方地址:https://github.com/vuejs/core

export function reactive(target: object) {
  // 如果是只读的,则不进行劫持
  if (isReadonly(target)) {
    return target
  }
  return createReactiveObject(
    target,
    false,
    mutableHandlers,
    mutableCollectionHandlers,
    reactiveMap
  )
}

其中参数中的方法展示如下:

export const mutableHandlers: ProxyHandler<object> = {
  get,
  set,
  deleteProperty,
  has,
  ownKeys
}


export const mutableCollectionHandlers: ProxyHandler<CollectionTypes> = {
  get: /*#__PURE__*/ createInstrumentationGetter(false, false)
}

export const reactiveMap = new WeakMap<Target, any>()

其中mytableHandlers对象定义了get、set、deleteProperty、has、ownkeys方法。 

reactive只是暴露给外部的一个api,真正处理的核心在createReactiveObject这个方法。如果不是对象类型直接返回。target 已经是个 proxy ,而且不是要求这个proxy 是已读的,但这个 proxy 是个响应式的,则直接返回这个 target。target已经是proxy对象,直接返回。target是不可观察的(__v_skip或者不可扩展对象),直接返回。只有Object、Array、Map、Set、WeakMap、WeakSet才可被监听。baseHandlers 是对进行基本类型的劫持,即 [Object,Array] ,collectionHandlers 是对集合类型的劫持, 即 [Set, Map, WeakMap, WeakSet]。

// 根据target 生成proxy实例
function createReactiveObject(
  target: Target,
  isReadonly: boolean,
  baseHandlers: ProxyHandler<any>,
  collectionHandlers: ProxyHandler<any>,
  proxyMap: WeakMap<Target, any>
) {
  if (!isObject(target)) {
    if (__DEV__) {
      console.warn(`value cannot be made reactive: ${String(target)}`)
    }
    return target
  }
  // target is already a Proxy, return it.
  // exception: calling readonly() on a reactive object
  if (
    target[ReactiveFlags.RAW] &&
    !(isReadonly && target[ReactiveFlags.IS_REACTIVE])
  ) {
    return target
  }
  // target already has corresponding Proxy
  const existingProxy = proxyMap.get(target)
  if (existingProxy) {
    return existingProxy
  }
  // only specific value types can be observed.
  const targetType = getTargetType(target)
  if (targetType === TargetType.INVALID) {
    return target
  }
  const proxy = new Proxy(
    target,
    targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
  )
  proxyMap.set(target, proxy)
  return proxy
}
 const proxy = new Proxy(
    target,
    targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
  )

 proxy的第二个参数,是根据targetType判断的,如果是Object、Array返回baseHandlers,否则返回collectionHandlers。其中baseHandlers中包含了get、set、deleteProperty、has、ownkeys方法。这些方法的封装,都利用了Reflect(反射)的api。

什么是反射呢?

Reflect是一个内置对象,它提供可拦截 JavaScript 操作的方法。这些方法与proxy代理的方法相同。Reflect不是一个函数对象,所以它是不可构造的。

  • Reflect上的操作能返回操作成功与否的反馈
  • 能够确保this的指向正确,从而总能在Reflect上获取对象的原始行为

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

成序猿@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值