目的
彻底弄懂Vue2 的数据更新原理,手写相关实现代码,让相关知识不再处于“忽悠阶段”

从MVVM模式说开去
侵入式和非侵入式
上帝的钥匙
Object.defineProperty()
数据劫持 / 数据代理
利用JavaScript引擎赋予的功能,检测对象属性变化
仅有"上帝的钥匙"不够,还需要设计一套精密的系统
Object.defineProperty()方法
Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
Object.defineProperty()方法接收三个参数,第一个参数是定义哪一个对象,第二个参数是定义什么属性,第三个参数是属性值。
Object.defineProperty()方法可以设置一些额外隐藏的属性
writeable可以定义属性是否可以写
enumerable可以定义属性是否可以被枚举,指的是在调用for in…方法的时候是否会被枚举
getter / setter
属性的getter函数,如果没有getter,则为<code>undefined</code>。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入<code>this</code>对象(由于继承关系,这里的<code>this</code>并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。
默认为<code>undefined</code>。
属性的setter函数,如果没有setter,则为<code>undefined</code>。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的<code>this</code>对象。
这里有一个小坑:用闭包存储get 和set 的值
defineReactive函数
getter / setter需要变量周转才能工作
使用defineReactive函数不需要设置临时变量,而是用闭包
递归侦测对象全部属性
数组的响应式处理
改写七个方法,以Array.prototype为原型,创建了一个arrayMethods对象,并且用es6的Object.setPrototypeOf方法,让数组的__proto__指向了arrayMethods,就可以调用新定义的七个函数方法。
依赖收集
需要用到数据的地方,称为依赖
Vue1.x,细粒度依赖,用到数据的DOM都是依赖
Vue2.x,中等粒度依赖,用到数组的组件是依赖
在getter中收集依赖,在setter中触发依赖
把依赖收集的代码封装成一个Dep 类,它专门用来管理依赖,每个Observer 的实例,成员中都有一个Dep 的实例;
Watcher 是一个中介,数据发生变化时通过Watcher 中转,通知组件
依赖就是Watcher 。只有Watch触发的getter才会收集依赖,哪个
Watcher 触发了getter,就把哪个Watch收集到Dep中。
Dep 使用发布订阅模式,当数据发生变化时,会循环依赖列表,把所
有的Watcher 都通知一遍。
代码实现的巧妙之处:Watcher把自己设置到全局的一个指定位置,然后读取数据,因为读取了数据,所以会触发这个数据的getter。在getter 中就能得到当前正在读取数据的Watcher,并把这个Watcher 收集到Dep 中。
完整代码