头图

副作用函数:指的是会产生副作用的函数;

JavaScript
let val = 1;//全局变量
function effect() {
  val = 2; //修改全局变量,产生副作用
}

effect函数执行时,对全局变量val产生了副作用,改变了其值。

响应式数据:

const obj = {text:"hello world"};
function effect(){
  //effect函数的执行读取obj.text
  document.body.innerHTML = obj.text;
}
obj.text = "hello Vue.js";

上面的副作用函数effect会设置bodyinnerText属性,其值为obj.text,第6行代码又修改了text的值,期望副作用函数重新执行,如果能实现这个目标,那么对于obj就是响应式数据。

如何才能让obj变成响应式数据呢?通过观察我们发现了两点线索:

▪当副作用函数effect执行时,会触发字段obj.text读取操作;

▪当修改obj.text的值时,会触发字段obj.text设置操作;

  如果能够拦截obj对象的读取设置操作,事情就迎刃而解了。当读取字段obj.text时,我们可以把副作用函数存储到一个“”中。
图片
  当设置obj.text时,再把副作用函数effect从“桶”里取出并执行。
图片
  按照上面的思路,使用Proxy来实现:

//创建一个副作用函数的桶
 const bucket = new Set();
 
 //原始数据
 const data = { text: "hello world" };
 
 //对原始数据的代理
 const obj = new Proxy(data, {
   //拦截读取操作
   get(traget, key) {
     //将副作用函数effect添加到副作用函数的桶中
     bucket.add(effect);
     //返回属性值
     return traget[key];
   },
   //拦截设置操作
   set(traget, key, newValue) {
     //设置属性值
     traget[key] = newValue;
     //把副作用函数从桶中取出来并执行
     bucket.forEach((fn) => fn());
     //返回true代表设置操作成功
     return true;
   },
 });
 

测试用例:

  function effect() {
    document.body.innerHTML = obj.text;
  }
  effect();
  setTimeout(() => {
    obj.text = "hello vue3";
  }, 1000);

1402bb277bd6589e5e43922438848b3.png
目前的实现数据响应式还存在很多缺陷,比如副作用函数的名字是写死的,下一章将完善响应式系统。


土豆
7 声望3 粉丝