问题集合

proxy与withProxy的区别

proxy:

instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers)

withProxy:

instance.withProxy = new Proxy(
        instance.ctx,
        RuntimeCompiledPublicInstanceProxyHandlers
)

在调用render的时候,proxy会作为他的第一个参数,如果开启render._rc = true,则会设置withProxy,调用render优先使用withProxy作为第一个参数。

// 继承PublicInstanceProxyHandlers 但是重写get和has
withProxy = extend({}, PublicInstanceProxyHandlers, {
    get(){
      // fast path for unscopables when using `with` block
      if ((key as any) === Symbol.unscopables) {
        return
      }
      return PublicInstanceProxyHandlers.get!(target, key, target)
    },
    has()
})

get:

RuntimeCompiledPublicInstanceProxyHandlers判断key是否等于Symbol.unscopables,如果相等则不做处理,直接return,不相等则和PublicInstanceProxyHandlers.get行为一致。目的是为了跳过get的一系列查询,优化代码性能。

has:

has方法用来拦截hasProperty操作,即判断对象是否具有某个属性时。handler.has() 方法是针对 in 操作符的代理方法。

PublicInstanceProxyHandlers.has:

查找的顺序为(都为instance的字段):

1.accessCache缓存中查找,这个缓存为key对应的类型,缓存起来可以快速在类型中查找

2.data中查找

3.setupState中查找

4.type.props中查找

5.ctx中查找

6.publicPropertiesMap,非instance字段,$data $el $props $attrs等

7.appContext.config.globalProperties,有且仅有一个的对象,所有有关系的组件都共同指向一个。

publicPropertiesMap:

const publicPropertiesMap: Record<
  string,
  (i: ComponentInternalInstance) => any
> = {
  $: i => i,
  $el: i => i.vnode.el,
  $data: i => i.data,
  $props: i => (__DEV__ ? shallowReadonly(i.props) : i.props),
  $attrs: i => (__DEV__ ? shallowReadonly(i.attrs) : i.attrs),
  $slots: i => (__DEV__ ? shallowReadonly(i.slots) : i.slots),
  $refs: i => (__DEV__ ? shallowReadonly(i.refs) : i.refs),
  $parent: i => i.parent && i.parent.proxy,
  $root: i => i.root && i.root.proxy,
  $emit: i => i.emit,
  $options: i => (__FEATURE_OPTIONS__ ? resolveMergedOptions(i) : i.type),
  $forceUpdate: i => () => queueJob(i.update),
  $nextTick: () => nextTick,
  $watch: __FEATURE_OPTIONS__ ? i => instanceWatch.bind(i) : NOOP
}

RuntimeCompiledPublicInstanceProxyHandlers.has:

判断查询的key,不能为'_'开头,且key不能在全局白名单中。

has(_: ComponentRenderContext, key: string) {
  const has = key[0] !== '_' && !isGloballyWhitelisted(key)
  if (__DEV__ && !has && PublicInstanceProxyHandlers.has!(_, key)) {
    warn(
      `Property ${JSON.stringify(
        key
      )} should not start with _ which is a reserved prefix for Vue internals.`
    )
  }
  return has
}
const GLOBALS_WHITE_LISTED =
  'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' +
  'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' +
  'Object,Boolean,String,RegExp,Map,Set,JSON,Intl'

export const isGloballyWhitelisted = /*#__PURE__*/ makeMap(GLOBALS_WHITE_LISTED)

总结

RuntimeCompiledPublicInstanceProxyHandlers继承publicInstanceProxyHandlers,前者get方法过滤key === Symbol.unscopables,has方法过滤基本类型和'_'开头的key。

results matching ""

    No results matching ""