Vue官网中的约束源码解释 -- 数据与方法
muwoo opened this issue · 0 comments
muwoo commented
当一个 Vue 实例被创建时,它向 Vue 的响应式系统中加入了其 data 对象中能找到的所有的属性。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
// 我们的数据对象
var data = { a: 1 }
// 该对象被加入到一个 Vue 实例中
var vm = new Vue({
data: data
})
// 获得这个实例上的属性
// 返回源数据中对应的字段
vm.a == data.a // => true
// 设置属性也会影响到原始数据
vm.a = 2
data.a // => 2
// ……反之亦然
data.a = 3
vm.a // => 3
为什么不是访问vm.$options.data.a
而是 vm.a
?
其实我们知道,为new Vue({data: ...})
的时候,会进行mergeOptions
,也就是吧所有的参数挂载到vm.$options
中,我们定义的data
也是会被挂载进去,那么,为什么我们可以通过vm.a
来取到我们想要的值呢?我们来看一下源码的实现:
// core/instance/state.js
function initData (vm: Component) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {}
...
}
Vue通过initData
函数,为实例vm
定义了一个_data
属性,他的值等于我们的vm.$options.data
。并做了函数处理,因为有可能我们是通过一个function
去return
一个data
。那到这一步,我们顶多可以通过this._data.xx
来访问属性,那如何实现this.xx
来访问呢?我们接着来看:
...
const keys = Object.keys(data)
let i = keys.length
while (i--) {
...
proxy(vm, `_data`, key)
}
...
我们省略了一些代码,主要来看核心的实现。首先我们会遍历data
中定义的属性,然后有一个proxy
这样的东西
const sharedPropertyDefinition = {
enumerable: true,
configurable: true,
get: noop,
set: noop
}
export function proxy (target: Object, sourceKey: string, key: string) {
sharedPropertyDefinition.get = function proxyGetter () {
return this[sourceKey][key]
}
sharedPropertyDefinition.set = function proxySetter (val) {
this[sourceKey][key] = val
}
Object.defineProperty(target, key, sharedPropertyDefinition)
}
这里用了一个Object.defineProperty
函数来定义了target = vm
,sourceKey = _data
,key = xx
。并改写了target.key
的get
和set
方法。
到这里我们就明白了,当我们访问this.xx
的时候,其实是被Object.defineProperty
拦截了,代理到this._data.xx
上面。