问题集合
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。