手寫vue3響應(yīng)式原理最終代碼

class Depend {
  constructor() {
    //set不允許重復
    this.reactiveFns = new Set();
  }
  //添加對應(yīng)的依賴
  addDepend(fn) {
    if (fn) {
      this.reactiveFns.add(fn);
    }
  }
  depend() {
    if (reactiveFn) {
      this.reactiveFns.add(reactiveFn);
    }
  }
  //通知數(shù)據(jù)發(fā)生變化,收集依賴
  notify() {
    this.reactiveFns.forEach((fn) => {
      fn();
    });
  }
}

//定義一個函數(shù),專門執(zhí)行響應(yīng)式函數(shù)

//形成閉包
let reactiveFn = null;

function watchFn(fn) {
  //一旦執(zhí)行函數(shù),將值賦值給reactiveFn
  reactiveFn = fn;
  fn();
  //函數(shù)保存起來,默認執(zhí)行一次
  //類似于wachEeffct(),自動收集依賴,立即執(zhí)行執(zhí)行一次

  reactiveFn = null;
  //執(zhí)行完操作之后,賦值為空,有可能對后續(xù)操作造成影響
}

//封裝一個函數(shù),來獲取對應(yīng)的depend對象
//利用weakMap,弱引用,即使obj為null,也不能對后續(xù)造成影響,
const objMap = new WeakMap();
function getDepend(obj, key) {
  //根據(jù)對象obj,找到對應(yīng)的map對象
  let map = objMap.get(obj);
  if (!map) {
    //weakMap的key必須要是對象,所以這里用Map()
    //如果拿不到,我們就new一個
    map = new Map();
    objMap.set(obj, map);
  }
  //根據(jù)key,找到對應(yīng)的depend對象
  let dep = map.get(key);
  if (!dep) {
    dep = new Depend();
    map.set(key, dep);
  }
  //所以一定可以返回拿到一個dep對象
  return dep;
}

//方案二。new Proxy() -> Vue3
//對obj里面的數(shù)據(jù)進行遍歷
function reactive(obj) {
  const objProxy = new Proxy(obj, {
    set: function (target, key, newValue, receiver) {
      Reflect.set(target, key, newValue, receiver);
      const dep = getDepend(target, key);
      dep.notify();
    },
    get: function (target, key, receiver) {
      const dep = getDepend(target, key);
      dep.depend();
      return Reflect.get(target, key, receiver);
    },
  });

  return objProxy;
}

//----------------------
const obj = reactive({
  name: "james",
  age: 38,
});
//凡是傳進watchFn函數(shù)里面就是響應(yīng)式的
watchFn(function foo() {
  console.log("foo name is", obj.name);
  console.log("foo age is ", obj.age);
  console.log("foo age is ", obj.age);
});

const user = reactive({
  height: 188,
  name: "peter",
});
watchFn(function bar() {
  console.log("user height", user.height);
  console.log("user name", user.name);
});

console.log("監(jiān)聽obj-age發(fā)生變化~~~~~~~~");
obj.age += 100;
console.log("監(jiān)聽name發(fā)生變化~~~~~~~~");
user.name += "123";
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容