先看如下代码:
js
const product = { price: 5, quantity: 2 };
let total = 0;
let effect = () => (total = product.price * product.quantity);
effect();
console.log(total); // --> 10
product.quantity = 3;
console.log(total); // --> 10
更改product.quantity = 3
后,再次打印total
,其值显然还是原来的10,因为product.quantity
并不是响应式属性。
要将其变成响应式,也就是需要追踪product.quantity
所关联的依赖,也就是effect
函数,然后在product.quantity
发生改变时触发effect
执行才可。
追踪单个属性
我们需要有个地方,追踪依赖了product.quantity
属性的effect
,只有这样,当该属性发生变动时,就能找到依赖该属性的effect
,然后遍历执行这些effect
。
而这个地方需要满足两个条件:
- 存储的依赖能自动去重
- 能遍历
Set
对象刚好满足上述条件。
修改代码,增加依赖收集对象,增加追踪依赖函数,如下:
js
const product = { price: 5, quantity: 2 };
let total = 0;
let effect = () => (total = product.price * product.quantity);
// 1.新增依赖收集对象
const dep = new Set();
// 2.新增追踪依赖函数
const track = () => {
dep.add(effect);
};
effect();
console.log(total); // --> 10
修改代码,增加依赖触发执行函数,如下:
js
const product = { price: 5, quantity: 2 };
let total = 0;
let effect = () => (total = product.price * product.quantity);
// 1.新增依赖收集对象
const dep = new Set();
// 2.新增追踪依赖函数
const track = () => {
dep.add(effect);
};
// 3.新增依赖触发执行函数
const trigger = () => {
dep.forEach((effect) => effect());
};
effect();
console.log(total); // --> 10
之后在修改属性值的时候,触发依赖的执行即可。
初始时,需要触发track
函数收集依赖,在product.quantity
修改的时候,触发trigger
函数,接着打印total
验证响应是否成功:
js
// ...省略以上代码
effect();
//4.初始时,触发track收集依赖
track();
console.log(total); // --> 10
product.quantity = 3;
// 5.修改变量后,触发triger执行依赖
trigger();
console.log(total); // --> 15
成功!!!可以看到,当我们修改了product.quantity
属性,然后执行trigger
函数后,total
值已经跟着一起改变!
总结
-
新增
dep
对象收集依赖,该对象是Set
结构。 -
新增
track
函数,该函数收集依赖了该属性的effect
,将其保存到dep
中。- 初始时触发
track
函数收集依赖。
- 初始时触发
-
新增
trigger
函数,该函数遍历dep
对象,并执行其中的effect
。- 在属性值进行更新后,触发
trigger
函数遍历执行effect
。
- 在属性值进行更新后,触发
问题
以上有两个问题:
- 只能追踪单个属性的依赖。
- 依赖的收集
track
和依赖的执行trigger
的触发都需要手动执行。
以上问题,在接下来两节中完善。