赞
踩
MVVM
模式,数据变化,视图会自动变化。model、view、view-model
。Vue
数据变化是非侵入式,React
数据变化和小程序数据变化是侵入式。Object.defineProperty()
, 是数据劫持/数据代理,利用JavaScript
引擎赋予的功能,检测对象属性变化。方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。同时,可以设置一些额外隐藏的属性。getter/setter
,用闭包存储get
和set
的值。get
,当访问该属性时,会调用此函数。set
,当属性值被修改时,会调用此函数。getter/setter
需要变量周转才能工作。使用defineReactive
函数不需要设置临时变量了,而是用闭包。Observer
,将一个正常的object
转换为每个层级的属性都是响应式(可以被侦测的)的object
,如下所示:observe(obj)
,看obj
身上有没有__ob__
。new Observer()
__ob__
上。defineReactive
。set
,里面有newValue
。这个newValue
也得被observe()
一下。push、pop、shift、unshift、splice、sort、reverse
,如下所示:Object.setPrototypeOf(o, arrayMethods)
o.__proto__ = arrayMethods
Vue1.x
,细粒度依赖,用到数据的DOM
都是依赖Vue2.x
,中等粒度依赖,用到数据的组件是依赖getter
中收集依赖,在setter
中触发依赖Dep
类和Watcher
类,如下所示:Dep
类,它专门用来管理依赖,每个Observer
的实例,成员中都有一个Dep
的实例Watcher
是一个中介,数据发生变化时通过Watcher
中转,通知组件Watcher
。只有Watcher
触发的getter
才会收集依赖,哪个Watcher
触发了getter
,就把哪个Watcher
收集到Dep
中Dep
使用发布订阅模式,当数据发生变化时,会循环依赖列表,把所Watcher
都通知一遍Watcher
把自己设置到全局的一个指定位置,然后读取数据,因为读取了数据,所以会触发这个数据的getter
。在getter
中就能得到当前正在读取数据的Watcher
,并把这个Watcher
收集到Dep
中二、数据响应式实现
Dep
,如下所示:subs
是英语subscribes
订阅者的意思,这个数组里面放的是Watcher
的实例。Dep.target
就是一个我们自己指定的全局的位置,你用window.target
也行,只要是全剧唯一,没有歧义就行。Dep
,代码如下所示:var uid = 0; export default class Dep { constructor() { console.log('我是DEP类的构造器'); this.id = uid++; this.subs = []; } addSub(sub) { this.subs.push(sub); } depend() { if (Dep.target) { this.addSub(Dep.target); } } notify() { console.log('我是notify'); const subs = this.subs.slice(); for (let i = 0, l = subs.length; i < l; i++) { subs[i].update(); } } };
observe
,如下所示:value
不是对象,什么都不做。ob
,判断返回。observe
,代码如下所示:import Observer from './Observer.js';
export default function (value) {
if (typeof value != 'object') return;
var ob;
if (typeof value.__ob__ !== 'undefined') {
ob = value.__ob__;
} else {
ob = new Observer(value);
}
return ob;
}
defineReactive
,如下所示:observe
,至此形成了递归。这个递归不是函数自己调用自己,而是多个函数、类循环调用。delete
。getter
,如果现在处于依赖收集阶段。setter
,当设置了新值,这个新值也要被observe
,发布订阅模式,通知dep
。defineReactive
,代码如下所示:import observe from './observe.js'; import Dep from './Dep.js'; export default function defineReactive(data, key, val) { const dep = new Dep(); if (arguments.length == 2) { val = data[key]; } let childOb = observe(val); Object.defineProperty(data, key, { enumerable: true, configurable: true, get() { console.log('你试图访问' + key + '属性'); if (Dep.target) { dep.depend(); if (childOb) { childOb.dep.depend(); } } return val; }, set(newValue) { console.log('你试图改变' + key + '属性', newValue); if (val === newValue) { return; } val = newValue; childOb = observe(newValue); dep.notify(); } }); };
utils
,代码如下所示:export const def = function (obj, key, value, enumerable) {
Object.defineProperty(obj, key, {
value,
enumerable,
writable: true,
configurable: true
});
};
array
,如下所示:Array.prototype``Array.prototype
为原型创建arrayMethods
对象,并暴露。7
个数组方法,备份原来的方法,因为push、pop
等7个函数的功能不能被剥夺。__ob__
取出来,__ob__
已经被添加了,为什么已经被添加了?因为数组肯定不是最高层,比如obj.g
属性是数组,obj
不能是数组,第一次遍历obj
这个对象的第一层的时候,已经给g
属性(就是这个数组)添加了__ob__
属性。push\unshift\splice
能够插入新项,现在要把插入的新项也要变为observe
的,splice
格式是splice(下标, 数量, 插入的新项)
。array
,代码如下所示:import { def } from './utils.js'; const arrayPrototype = Array.prototype; export const arrayMethods = Object.create(arrayPrototype); const methodsNeedChange = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse' ]; methodsNeedChange.forEach(methodName => { const original = arrayPrototype[methodName]; def(arrayMethods, methodName, function () { const result = original.apply(this, arguments); const args = [...arguments]; const ob = this.__ob__; let inserted = []; switch (methodName) { case 'push': case 'unshift': inserted = args; break; case 'splice': inserted = args.slice(2); break; } if (inserted) { ob.observeArray(inserted); } console.log('啦啦啦'); ob.dep.notify(); return result; }, false); });
Watcher
,代码如下所示:import Dep from "./Dep"; var uid = 0; export default class Watcher { constructor(target, expression, callback) { console.log('我是Watcher类的构造器'); this.id = uid++; this.target = target; this.getter = parsePath(expression); this.callback = callback; this.value = this.get(); } update() { this.run(); } get() { Dep.target = this; const obj = this.target; var value; try { value = this.getter(obj); } finally { Dep.target = null; } return value; } run() { this.getAndInvoke(this.callback); } getAndInvoke(cb) { const value = this.get(); if (value !== this.value || typeof value == 'object') { const oldValue = this.value; this.value = value; cb.call(this.target, value, oldValue); } } }; function parsePath(str) { var segments = str.split('.'); return (obj) => { for (let i = 0; i < segments.length; i++) { if (!obj) return; obj = obj[segments[i]] } return obj; }; }
Observer
,如下所示:Observer
的实例身上,都有一个dep
。this
,一定要注意,构造函数中的this
不是表示类本身,而是表示实例)添加了__ob__
属性,值是这次new
的实例。Observer
类的目的是:将一个正常的object
转换为每个层级的属性都是响应式(可以被侦测的)的object
,检查它是数组还是对象。arrayMethods
,让这个数组变的observe
。observe
。Observer
,代码如下所示:import { def } from './utils.js'; import defineReactive from './defineReactive.js'; import { arrayMethods } from './array.js'; import observe from './observe.js'; import Dep from './Dep.js'; export default class Observer { constructor(value) { this.dep = new Dep(); def(value, '__ob__', this, false); if (Array.isArray(value)) { Object.setPrototypeOf(value, arrayMethods); this.observeArray(value); } else { this.walk(value); } } walk(value) { for (let k in value) { defineReactive(value, k); } } observeArray(arr) { for (let i = 0, l = arr.length; i < l; i++) { observe(arr[i]); } } };
index
,代码如下所示:import observe from './observe.js'; import Watcher from './Watcher.js'; var obj = { a: { m: { n: 5 } }, b: 10, c: { d: { e: { f: 6666 } } }, g: [22, 33, 44, 55] }; observe(obj); new Watcher(obj, 'a.m.n', (val) => { console.log('★我是watcher,我在监控a.m.n', val); }); obj.a.m.n = 88; console.log(obj);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。