Vue源码探究之状态初始化(4)
与 props 的处理类似,initData 函数的作用也是为了对数据建立观察的依赖关系,并且代理数据到私有变量 _data 上,另外包括了对 data 与其他配置对象属性的键名冲突的检测。
initComputed
// 设置computedWatcherOptions对象
const computedWatcherOptions = { computed: true }
// 定义initComputed函数,接受实例vm,和computed对象
function initComputed (vm: Component, computed: Object) {
// $flow-disable-line
// 定义watchers和实例_computedWatchers属性,初始赋值空对象
const watchers = vm._computedWatchers = Object.create(null)
// 是否是服务器渲染,computed属性在服务器渲染期间只能是getter
// computed properties are just getters during SSR
const isSSR = isServerRendering()
// 遍历computed
for (const key in computed) {
// 获取用户定义的值
const userDef = computed[key]
// 如果用户定义的是函数则赋值给getter否则j将userDef.get方法赋值给getter
const getter = typeof userDef === 'function' ? userDef : userDef.get
// 非生产环境抛出缺少计算属性错误警告
if (process.env.NODE_ENV !== 'production' && getter == null) {
warn(
`Getter is missing for computed property "${key}".`,
vm
)
}
// 非服务器渲染下
if (!isSSR) {
// 为计算属性创建内部监视器
// create internal watcher for the computed property.
watchers[key] = new Watcher(
vm,
getter || noop,
noop,
computedWatcherOptions
)
}
// 组件定义的内部计算属性已经在组件的原型上定义好了
// 所以这里只要关注实例初始化时用户定义的计算属性
// component-defined computed properties are already defined on the
// component prototype. We only need to define computed properties defined
// at instantiation here.
// 键名非实例根属性时,定义计算属性,具体参照defineComputed函数
if (!(key in vm)) {
defineComputed(vm, key, userDef)
// 非生产环境下,检测与data属性名的冲突并给出警告
} else if (process.env.NODE_ENV !== 'production') {
if (key in vm.$data) {
warn(`The computed property "${key}" is already defined in data.`, vm)
} else if (vm.$options.props && key in vm.$options.props) {
warn(`The computed property "${key}" is already defined as a prop.`, vm)
}
}
}
}
// 定义并导出defineComputed哈数
// 接收实例target,计算属性键名key,计算属性值userDef参数
export function defineComputed (
target: any,
key: string,
userDef: Object | Function
) {
// 在非服务器渲染下设置缓存
const shouldCache = !isServerRendering()
// 计算属性值是函数时
if (typeof userDef === 'function') {
// 设置计算属性的getter,setter为空函数
sharedPropertyDefinition.get = shouldCache
? createComputedGetter(key)
: userDef
sharedPropertyDefinition.set = noop
} else {
// 当计算属性是对象时,设置计算属性的getter和setter
sharedPropertyDefinition.get = userDef.get
? shouldCache && userDef.cache !== false
? createComputedGetter(key)
: userDef.get
: noop
sharedPropertyDefinition.set = userDef.set
? userDef.set
: noop
}
// 非生产环境下,如果没哟定义计算属性的setter
// 想设置计算属性时给出警告
if (process.env.NODE_ENV !== 'production' &&
sharedPropertyDefinition.set === noop) {
sharedPropertyDefinition.set = function () {
warn(
`Computed property "${key}" was assigned to but it has no setter.`,
this
)
}
}
// 以重新设置的属性描述符为基础在实例对象上定义计算属性
Object.defineProperty(target, key, sharedPropertyDefinition)
}
// 定义createComputedGetter,创建计算属性getter
// 目的是在非服务器渲染情况下建立计算属性的观察依赖,
// 并根据其依赖属性返回计算后的值
function createComputedGetter (key) {
return function computedGetter () {
const watcher = this._computedWatchers && this._computedWatchers[key]
if (watcher) {
watcher.depend()
return watcher.evaluate()
}
}
}
内容版权声明:除非注明,否则皆为本站原创文章。
