Open muwoo opened 6 years ago
当一个 Vue 实例被创建时,它向 Vue 的响应式系统中加入了其 data 对象中能找到的所有的属性。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。 // 我们的数据对象 var data = { a: 1 }
当一个 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```来取到我们想要的值呢?我们来看一下源码的实现: ```js // 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来访问呢?我们接着来看:
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这样的东西
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上面。
Object.defineProperty
target = vm
sourceKey = _data
key = xx
target.key
get
set
// 该对象被加入到一个 Vue 实例中 var vm = new Vue({ data: data })
// 获得这个实例上的属性 // 返回源数据中对应的字段 vm.a == data.a // => true
// 设置属性也会影响到原始数据 vm.a = 2 data.a // => 2
// ……反之亦然 data.a = 3 vm.a // => 3
Vue通过
initData
函数,为实例vm
定义了一个_data
属性,他的值等于我们的vm.$options.data
。并做了函数处理,因为有可能我们是通过一个function
去return
一个data
。那到这一步,我们顶多可以通过this._data.xx
来访问属性,那如何实现this.xx
来访问呢?我们接着来看:我们省略了一些代码,主要来看核心的实现。首先我们会遍历
data
中定义的属性,然后有一个proxy
这样的东西这里用了一个
Object.defineProperty
函数来定义了target = vm
,sourceKey = _data
,key = xx
。并改写了target.key
的get
和set
方法。 到这里我们就明白了,当我们访问this.xx
的时候,其实是被Object.defineProperty
拦截了,代理到this._data.xx
上面。