|Vue.js源码全方位深入解析,快人一步进名企-完结( 四 )


return props[key



else if (setupState !== EMPTY_OBJ && hasOwn(setupState key)) <{p>
accessCache[key
= 0
// 从 setupState 中取数据
return setupState[key


else if (data !== EMPTY_OBJ && hasOwn(data key)) <{p>
accessCache[key
= 1
// 从 data 中取数据
return data[key


else if (
type.props &&
hasOwn(normalizePropsOptions(type.props)[0
key)) <{p>
accessCache[key
= 2
// 从 props 中取数据
return props[key


else if (ctx !== EMPTY_OBJ && hasOwn(ctx key)) <{p>
accessCache[key
= 3
// 从 ctx 中取数据
return ctx[key


else <{p>
// 都取不到
accessCache[key
= 4


const publicGetter = publicPropertiesMap[key

let cssModule globalProperties
// 公开的 $xxx 属性或方法
if (publicGetter) <{p>
return publicGetter(instance)

else if (
// css 模块 , 通过 vue-loader 编译的时候注入
(cssModule = type.__cssModules) &&
(cssModule = cssModule[key
)) <{p>
return cssModule

else if (ctx !== EMPTY_OBJ && hasOwn(ctx key)) <{p>
// 用户自定义的属性 , 也用 `$` 开头
accessCache[key
= 3
return ctx[key


else if (
// 全局定义的属性
((globalProperties = appContext.config.globalProperties)
hasOwn(globalProperties key))) <{p>
return globalProperties[key


else if ((process.env.NODE_ENV !== 'production') &&
currentRenderingInstance && key.indexOf('__v') !== 0) <{p>
if (data !== EMPTY_OBJ && key[0
=== '$' && hasOwn(data key)) <{p>
// 如果在 data 中定义的数据以 $ 开头 , 会报警告 , 因为 $ 是保留字符 , 不会做代理
warn(`Property ${JSON.stringify(key) must be accessed via $data because it starts with a reserved ` +
`character and is not proxied on the render context.`)

else <{p>
// 在模板中使用的变量如果没有定义 , 报警告
warn(`Property ${JSON.stringify(key) was accessed during render ` +
`but is not defined on instance.`)




可以看到 , 函数首先判断 key 不以 $ 开头的情况 , 这部分数据可能是 setupState、data、props、ctx 中的一种 , 其中 data、props 我们已经很熟悉了;setupState 就是 setup 函数返回的数据 , 稍后我们会详细说;ctx 包括了计算属性、组件方法和用户自定义的一些数据 。 如果 key 不以 $ 开头 , 那么就依次判断 setupState、data、props、ctx 中是否包含这个 key , 如果包含就返回对应值 。 注意这个判断顺序很重要 , 在 key 相同时它会决定数据获取的优先级 , 举个例子:
<template>
<p></p>
</template>
<script>
import { reffrom 'vue'
export default <{p>
data() <{p>
return <{p>
msg: 'msg from data'


setup() <{p>
const msg = ref('msg from setup')
return <{p>
msg



</script>
我们在 data 和 setup 中都定义了 msg 变量 , 但最终输出到界面上的是\"msg from setup\" , 这是因为 setupState 的判断优先级要高于 data 。 再回到 get 函数中 , 我们可以看到这里定义了 accessCache 作为渲染代理的属性访问缓存 , 它具体是干什么的呢?组件在渲染时会经常访问数据进而触发 get 函数 , 这其中最昂贵的部分就是多次调用 hasOwn 去判断 key 在不在某个类型的数据中 , 但是在普通对象上执行简单的属性访问相对要快得多 。 所以在第一次获取 key 对应的数据后 , 我们利用 accessCache[key