feat: vue2 reactive implementation

This commit is contained in:
amandakelake
2022-02-12 09:57:15 +08:00
parent 999b33f31f
commit 0dc0876d65
2 changed files with 108 additions and 0 deletions
@@ -45,6 +45,7 @@ Function.prototype.bind = function (context) {
var args = [...arguments].slice(1);
return function Fn() {
// 判断是否用于构造函数
if (this instanceof Fn) {
return new _this(args, ...arguments);
}
+107
View File
@@ -0,0 +1,107 @@
class Observer {
constructor(data) {
this.walk(data);
}
walk(data) {
// 此处简化,只处理对象
if (data instanceof Object) {
for (let key in data) {
if (data.hasOwnProperty(key)) {
this.defineReactive(data, key, data[key]);
}
}
}
}
/**
* getter中收集依赖,setter中触发依赖
*/
defineReactive(data, key, val) {
const _this = this;
// 每个key实例一个dep
const dep = new Dep();
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function () {
// 将当前的watcher实例收集到依赖中
Dep.target && dep.addSub(Dep.target);
return val;
},
set: function (newVal) {
if (val === newVal) {
return;
}
val = newVal;
// 递归遍历新值
_this.walk(newVal);
// 触发依赖
dep.notify();
},
});
}
}
class Dep {
static target;
constructor() {
this.subs = [];
}
addSub(sub) {
if (sub && sub.update) {
this.subs.push(sub);
}
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
class Watcher {
constructor(data, key, callback) {
// getter收集依赖,getter不能传参,所以通过闭包传进去
Dep.target = this;
this.data = data;
this.key = key;
this.callback = callback;
this.value = data[key];
// 完成某个属性的依赖收集后,清空Dep.target
// notify方法会重新调用getter(重新获取值,重新收集依赖)
// 清空Dep.target,防止notify中不停绑定Watcher与Dep -> 代码死循环
Dep.target = null;
}
/**
* 更新视图 vm._render / 执行user逻辑
*/
update() {
this.value = this.data[this.key];
this.callback(this.value);
}
}
const data = {
a: 1,
b: 1,
};
new Observer(data);
new Watcher(data, 'a', (value) => {
console.log('watcher update 新值 -> ' + value);
});
data.a = 2;
data.a = {
c: 'c',
};
new Watcher(data.a, 'c', (value) => {
console.log('watcher update 新值 -> ' + value);
});
data.a.c = 'hello new world';