We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vue 2.x 的响应式主要就是利用Object.defineProperty来重新定义data里的每个属性。
Object.defineProperty
data
这篇只写了观察属性,没有提及收集依赖
let vm = new Vue({ el: '#app', data() { return { msg: 'hello', school: { name: 'lmh', age: 24 }, arr: [1, 2, 3] } } })
当我们创建一个Vue实例的时候,传入了data,可以是一个对象,也可以是一个函数
Vue
所以在vue里面,需要对data做接收 new Vue的时候,需要经过初始化阶段,其中就有初始化数据的阶段(把数据重定义为响应式的)。
vue
new Vue
import { initState } from './observe'; function Vue(options) { this._init(options); // 初始化 } Vue.prototype._init = function(options) { let vm = this; // 把this叫成vm,方便表示this是实例,方便看,不用多想this指向 vm.$options = options; // MVVM原理,数据响应式,需要重新初始化数据 initState(vm); }; export default Vue;
看一下initState函数是什么初始化数据的
initState
import Observe from './observe'; export function initState(vm) { let opts = vm.$options; if (opts.data) { initData(vm); // 如果有数据,就初始化数据 } } function initData(vm) { let { data } = vm.$options; // 给vm新加了一个_data属性。需要判断一下,data是函数还是数据。函数的话,要执行拿到数据 data = vm._data = typeof data === 'function' ? data.call(vm) : data; // 不太想得明白,为啥要call observe(vm._data); // 对属性进行观察 } export function observe(data) { if (typeof data !== 'object' || data == null) { return; // 不过不是对象或者为空,就不用观察 } return new Observe(data); }
接下来到了核心了:Observe观察
Observe
// 监控,就是通过循环,给每个属性重新定义 class Observe { constructor(data) { this.walk(data); } // 遍历data里的属性,给每个属性都用defineProperty重新定义 walk(data) { let keys = Object.keys(data); for (let i = 0; i < keys.length; i++) { let key = keys[i]; let value = data[key]; defineReactive(data, key, value); } } } export function defineReactive(data, key, value) { observe(value); // 递归,如果value还是对象,那么同样给里面的属性都重新定义成响应式的 Object.defineProperty(data, key, { // 定义、修改data上的,key属性 get() { return value; }, set(newValue) { if (newValue === value) { return; } value = newValue; console.log('更新视图') } }); } export default Observe;
然后,就可以通过vm._data.msg 拿到一开始创建vue实例的时候创建的msg的数据了。
vm._data.msg
msg
但是,在用的时候,我们都是通过vm.msg拿到的数据,而不是vm._data.msg。对于这个,我们只需要再做一层代理,使得我们通过vm.msg拿数据的时候,返回vm._data.msg的数据就可以了。
vm.msg
看回上面第二段的initData函数,在这里,我们给vm新添加了一个_data属性,并且把参数里的data的值挂到了上面。这里,我们就做一下刚才说的所需要的处理:
initData
vm
_data
function initData(vm) { let { data } = vm.$options; // 给vm新加了一个_data属性。需要判断一下,data是函数还是数据。函数的话,要执行拿到数据 data = vm._data = typeof data === 'function' ? data.call(vm) : data; // 不太想得明白,为啥要call // 添加一个代理,使得在获取数据的时候,不需要再vm._data.xx得到数据,而是直接vm.xx就可以拿到数据 for (let key in data) { // 遍历每一个属性,给每个属性都加上代理 proxy(vm, '_data', key); } observe(vm._data); // 对属性进行观察 } function proxy(vm, source, key) { Object.defineProperty(vm, key, { // 给vm加上data里的属性 get() { // 如果 vm.msg,实际上返回vm._data.msg return vm[source][key] }, set(newValue) { return vm[source][key] = newValue; } }) }
这样,就可以直接获取到vm.msg的值了。
不过,这里我还有问题没有搞懂,如果获取vm.school或者vm._data.school的值,打印出来是{},需要深拷贝JSON.parse(JSON.stringify(vm.school)才可以正常显示。
vm.school
vm._data.school
{}
JSON.parse(JSON.stringify(vm.school)
在用实际的vue的时候也遇到过,不知道为啥。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
Vue 2.x 的响应式主要就是利用
Object.defineProperty
来重新定义data
里的每个属性。这篇只写了观察属性,没有提及收集依赖
当我们创建一个
Vue
实例的时候,传入了data
,可以是一个对象,也可以是一个函数所以在
vue
里面,需要对data
做接收new Vue
的时候,需要经过初始化阶段,其中就有初始化数据的阶段(把数据重定义为响应式的)。看一下
initState
函数是什么初始化数据的接下来到了核心了:
Observe
观察然后,就可以通过
vm._data.msg
拿到一开始创建vue
实例的时候创建的msg
的数据了。但是,在用的时候,我们都是通过
vm.msg
拿到的数据,而不是vm._data.msg
。对于这个,我们只需要再做一层代理,使得我们通过vm.msg
拿数据的时候,返回vm._data.msg
的数据就可以了。看回上面第二段的
initData
函数,在这里,我们给vm
新添加了一个_data
属性,并且把参数里的data
的值挂到了上面。这里,我们就做一下刚才说的所需要的处理:这样,就可以直接获取到
vm.msg
的值了。不过,这里我还有问题没有搞懂,如果获取

vm.school
或者vm._data.school
的值,打印出来是{}
,需要深拷贝JSON.parse(JSON.stringify(vm.school)
才可以正常显示。在用实际的vue的时候也遇到过,不知道为啥。
The text was updated successfully, but these errors were encountered: