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


去缓存数据 , 下一次再次根据 key 查找数据 , 我们就可以直接通过 accessCache[key
获取对应的值 , 就不需要依次调用 hasOwn 去判断了 。 这也是一个性能优化的小技巧 。
如果 key 以$开头 , 那么接下来又会有一系列的判断 , 首先判断是不是 Vue.js 内部公开的$xxx 属性或方法(比如 $parent);然后判断是不是 vue-loader 编译注入的 css 模块内部的 key;接着判断是不是用户自定义以 $开头的 key;最后判断是不是全局属性 。 如果都不满足 , 就剩两种情况了 , 即在非生产环境下就会报两种类型的警告 , 第一种是在 data 中定义的数据以$开头的警告 , 因为$是保留字符 , 不会做代理;第二种是在模板中使用的变量没有定义的警告 。 接下来是 set 代理过程 , 当我们修改 instance.ctx 渲染上下文中的属性的时候 , 就会进入 set 函数 。 我们来看一下 set 函数的实现:
const PublicInstanceProxyHandlers = <{p>
set ({ _: instancekey value) <{p>
const { data setupState ctx= instance
if (setupState !== EMPTY_OBJ && hasOwn(setupState key)) <{p>
// 给 setupState 赋值
setupState[key
= value

else if (data !== EMPTY_OBJ && hasOwn(data key)) <{p>
// 给 data 赋值
data[key
= value

else if (key in instance.props) <{p>
// 不能直接给 props 赋值
(process.env.NODE_ENV !== 'production') &&
warn(`Attempting to mutate prop \"${key\". Props are readonly.` instance)
return false

if (key[0
=== '$' && key.slice(1) in instance) <{p>
// 不能给 Vue 内部以 $ 开头的保留属性赋值
(process.env.NODE_ENV !== 'production') &&
warn(`Attempting to mutate public property \"${key\". ` +
`Properties starting with $ are reserved and readonly.` instance)
return false

else <{p>
// 用户自定义数据赋值
ctx[key
= value

return true


结合代码来看 , 函数主要做的事情就是对渲染上下文 instance.ctx 中的属性赋值 , 它实际上是代理到对应的数据类型中去完成赋值操作的 。 这里仍然要注意顺序问题 , 和 get 一样 , 优先判断 setupState , 然后是 data , 接着是 props 。 我们对之前的例子做点修改 , 添加一个方法:
<template>
<p>< msg ></p>
<button @click=\"random\">Random msg</button>
</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


methods: <{p>
random() <{p>
this.msg = Math.random()



</script>
我们点击按钮会执行 random 函数 , 这里的 this 指向的就是 instance.ctx , 我们修改 this.msg 会触发 set 函数 , 所以最终修改的是 setupState 中的 msg 对应的值 。 注意 , 如果我们直接对 props 中的数据赋值 , 在非生产环境中会收到一条警告 , 这是因为直接修改 props 不符合数据单向流动的设计思想;如果对 Vue.js 内部以 $ 开头的保留属性赋值 , 同样也会收到一条警告 。 如果是用户自定义的数据 , 比如在 created 生命周期内定义的数据 , 它仅用于组件上下文的共享 , 如下所示:
export default <{p>created() <{p>this.userMsg = 'msg from user'


当执行 this.userMsg 赋值的时候 , 会触发 set 函数 , 最终 userMsg 会被保留到 ctx 中 。 最后是 has 代理过程 , 当我们判断属性是否存在于 instance.ctx 渲染上下文中时 , 就会进入 has 函数 , 这个在平时项目中用的比较少 , 同样来举个例子 , 当执行 created 钩子函数中的 'msg' in this 时 , 就会触发 has 函数 。