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
存在