vue学习笔记之二:object的变化侦测Watcher
同样的,展示我们可以跑起来的测试代码。当然这是翻看各个类后,按我自己理解整理出来的。原文有export default都取消了,方便一个文件测试。新增一个文件vuetest02.js,将以下代码拷贝
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
// removeSub(sub) {
// remove(this.subs, sub);
// }
depend() {
if (window.target) {
this.addSub(window.target)
}
}
notify() {
const subs = this.subs.slice();
for (let i = 0; i < subs.length; i++) {
subs[i].update();
}
}
}
const bailRE = /[^\w.$]/
function parsePath(path){
if (bailRE.test(path)) {
return;
}
const segments = path.split('.');
return function (obj) {
if (!obj) return;
//console.log(obj);
for (let i = 0; i < segments.length; i++) {
//console.log(segments[i]);
obj = obj[segments[i]];
}
return obj;
}
}
var window = {};//模拟页面全局属性
class Watcher {
constructor(vm, expOrFn, cb) {
this.vm = vm;
// 执行this.getter(),就可以获取到data.a.b.c的内容
this.getter = parsePath(expOrFn);
this.cb = cb;
this.value = this.get();
console.log("this.value..." + this.value);
}
get() {
window.target = this;
let value = this.getter.call(this.vm, this.vm);
window.target = undefined;
return value;
}
update() {
const oldValue = this.value;
this.value = this.get();
this.cb.call(this.vm, this.value, oldValue);
}
}
class Observer {
constructor(value) {
this.value = value;
if (!Array.isArray(value)) {
this.walk(value);
}
}
walk(obj) {
const keys = obj.keys(obj);
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i], obj.keys[i])
}
}
}
function defineReactive(data, key, val) {
// 新增,递归子属性
if (typeof val == 'object') {
new Observer(val);
}
let dep = new Dep();
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function () {
dep.depend();
return val;
},
set: function (newVal) {
if (val === newVal) {
return;
}
val = newVal;
dep.notify();
}
})
}
//与01测试一样的数据准备。
var base = {};
defineReactive(base, "name", "kevin");
//准备一个修改DOM的方法。就是说只要属性变化了,就帮我调用这个方法
function updateVm(vm, newVal, oldValue) {
console.log(`将控件的外观按新值变化...newVal=${newVal},oldValue=${oldValue}`);
}
let watch = new Watcher(base, "name", updateVm);
base.name = "witty";
base.name = "witty2";
base.name = "witty3";
console.log("测试完成。")
在命令窗口运行:node vuetest02.js
你会发现有两个问题,以下是测试的截图

第一个问题,updateVm为什么newVal是一个旧值,其实是我并不了解call的方法是什么含义
Function.call(obj,[param1[,param2[,…[,paramN]]]]) obj:这个对象将代替Function类里this对象 params:这个是一个参数列表
原来第一个参数实际上是代表this,于是调用updateVm如下:
//准备一个修改DOM的方法。就是说只要属性变化了,就帮我调用这个方法
function updateVm(newVal, oldValue) {
console.log(`this=${this}`);
console.log(`将控件的外观按新值变化...newVal=${newVal},oldValue=${oldValue}`);
}
第二个问题,是书本上的代码就有这个问题存在,其实每get一次都会加一次“依赖收集”,解决也很容易,把window.target=this这一句从get方法中删除,改放在构造函数调用get的语句之前就行了。

浙公网安备 33010602011771号