vue.js动态数据绑定学习笔记

2020-06-13 10:42:10易采站长站整理

enumerable: true,
configurable: true,
get: function() {
// 直接返回属性值
return val;
},
set: function(newVal) {
if (newVal === val) {
return;
}
// 值发生变化时修改闭包中的 val,
// 保证在触发 getter 时返回正确的值
val = newVal;

// 对新赋的值进行递归,防止赋的值为对象的情况
childObj = observe(newVal);
}
});
}

最后补充上 observe 函数,也即 Hue 构造函数中调用的 observe 函数:


function observe(val) {
// 若 val 是对象且非数组,则 new 一个 Observer 实例,val 作为参数
// 简单点说:是对象就继续。
if (!Array.isArray(val) && typeof val === "object") {
return new Observer(val);
}
}

这样一来就对 data 的所有子孙属性(不知有没有这种说法。。)都进行了“劫持”。显然到目前为止,这并没什么用,或者说如果只做到这里,那么和什么都不做没差别。于是 Dep 上场了。我认为理解 Dep 与 Observer 和 Watcher 之间的联系是最重要的,先来谈谈 Dep 在 Observer 里做了什么。

Observer & Dep

在每一次 defineReactive 函数被调用之后,都会在闭包中新建一个 Dep 实例,即 let dep = new Dep()。Dep 提供了一些方法,先来说说 notify 这个方法,它做了什么事?就是在属性值发生变化的时候通知 Dep,那么我们的代码可以增加如下:


function defineReactive(obj, key, val) {
let childObj = observe(val);
const dep = new Dep();

Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function() {
return val;
},
set: function(newVal) {
if (newVal === val) {
return;
}

val = newVal;
childObj = observe(newVal);

// 发生变动
dep.notify();
}
});
}

如果仅考虑 Observer 与 Dep 的联系,即有变动时通知 Dep,那么这里就算完了,然而在 vue.js 的源码中,我们还可以看到一段增加在 getter 中的代码:


// ...
get: function() {
if (Dep.target) {
dep.depend();
}
return val;
}
// ...

这个 depend 方法呢,它又做了啥?答案是为闭包中的 Dep 实例添加了一个 Watcher 的订阅,而 Dep.target 又是啥?他其实是一个 Watcher 实例,???一脸懵逼,先记住就好,先看一部份的 Dep 源码:


// 标识符,在 Watcher 中有用到,先不用管
let uid = 0;

function Dep() {
this.id = uid++;
this.subs = [];
}

Dep.prototype.depend = function() {