key 时,获取默认值并在对象上定义 __ob__ ,最后返回相应的值,在这里不做展开。
这里我们先跳过 defineReactive ,看最后
if (!(key in vm)) {
proxy(vm, '_props', key)
}
其中 proxy 方法:
function proxy (target, sourceKey, key) {
sharedPropertyDefinition.get = function proxyGetter () {
return this[sourceKey][key]
}
sharedPropertyDefinition.set = function proxySetter (val) {
this[sourceKey][key] = val
}
Object.defineProperty(target, key, sharedPropertyDefinition)
}
在 vm 不存在 key 属性时,通过 Object.defineProperty 使得我们能通过 vm[key] 访问到 vm._props[key] 。
defineReactive
在 initProps 中,我们了解到其首先根据用户定义的 vm.$options.props 对象,通过对父组件设置的传值对象 vm.$options.propsData 进行数据校验,返回有效值并保存到 vm._props ,同时保存相应的 key 到 vm.$options._propKeys 以便进行子组件的 props 数据更新,最后利用 getter/setter 存取器属性,将 vm[key] 指向对 vm._props[key] 的操作。但其中跳过了最重要的 defineReactive ,现在我们将通过阅读 defineReactive 源码,了解响应式数据背后的实现原理。
// src/core/observer/index.js
export function defineReactive (
obj,
key,
val,
customSetter,
shallow
) {
const dep = new Dep()
const property = Object.getOwnPropertyDescriptor(obj, key)
if (property && property.configurable === false) {
return
}
// cater for pre-defined getter/setters
const getter = property && property.get
const setter = property && property.set
if ((!getter || setter) && arguments.length === 2) {
val = obj[key]
}
let childOb = !shallow && observe(val)
...
}
首先 const dep = new Dep() 实例化了一个 dep ,在这里利用闭包来定义一个依赖项,用以与特定的 key 相对应。因为其通过 Object.defineProperty 重写 target[key] 的 getter/setter 来实现数据的响应式,因此需要先判断对象 key 的 configurable 属性。接着
if ((!getter || setter) && arguments.length === 2) {
val = obj[key]
}
arguments.length === 2 意味着调用 defineReactive 时未传递 val 值,此时 val 为 undefined ,而 !getter || setter 判断条件则表示如果在 property 存在
