<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      vue中的觀察者模式和發布訂閱者模式

      Posted on 2021-10-21 18:15  過鹿人  閱讀(1090)  評論(0)    收藏  舉報


      觀察者模式

      目標者對象和觀察者對象有相互依賴的關系,觀察者對某個對象的狀態進行觀察,如果對象的狀態發生改變,就會通知所有依賴這個對象的觀察者,

      目標者對象 Subject,擁有方法:添加 / 刪除 / 通知 Observer;

      觀察者對象 Observer,擁有方法:接收 Subject 狀態變更通知并處理;

      目標對象 Subject 狀態變更時,通知所有 Observer。

       

      Vue中響應式數據變化是觀察者模式 每個響應式屬性都有dep,dep存放了依賴這個屬性的watcher,watcher是觀測數據變化的函數,如果數據發生變化,dep就會通知所有的觀察者watcher去調用更新方法。因此, 觀察者需要被目標對象收集,目的是通知依賴它的所有觀察者。那為什么watcher也要存放dep呢?是因為當前正在執行的watcher需要知道此時是哪個dep通知了自己。

       

      在beforeCreate之后,created之前調用observe(data)初始化響應式數據,以下是簡化版代碼(沒有處理數組的劫持)
      class Observer {
          // 需要對value的屬性描述重新定義
          constructor(value) {
            this.walk(value); // 初始化的時候就對數據進行監控
          }
          walk(data) {
            Object.keys(data).forEach((key) => {
              defineReactive(data, key, data[key]);
            });
          }
        }
        
        function defineReactive(data, key, value) {
          // value 可能是一個對象,要遞歸劫持,所以數據不能嵌套太深
          observe(value);
          let dep = new Dep();
          Object.defineProperty(data, key, {
            get() {
              // 如果有 watcher,就讓 watcher 記住 dep,防止產生重復的 dep, 同時 dep 也收集此 watcher
              if (Dep.target) {
                dep.depend();
              }
              return value;
            },
            set(newVal) {
              // 數據沒變動則不處理
              if (value === newVal) return;
              observe(newVal); // 如果新值是個對象,遞歸攔截
              value = newVal; // 設置新的值
              dep.notify(); // 通知收集的 watcher 去更新
            },
          });
      }
      function observe(data) {
          // 不是對象則不處理,isObject是用來判斷是否為對象的函數
          if (Object.prototype.toString.call(data)!== '[object Object]') return;
          // 通過類來實現數據的觀測,方便擴展,生成實例
          return new Observer(data);
      }
      observe(data)
       
      在created之后,mouted之前調用mountComponent掛載組件,以下是簡化版代碼(沒有處理watch和computed的watcher)
      class Dep {
          static target = null
          constructor() {
            this.id = id++;
            this.subs = []; // 存放依賴的watcher
          }
          depend() {
            // 讓正在執行的watcher記錄dep,同時dep也會記錄watcher
            Dep.target.addDep(this);
          }
          addSub(watcher) {
            // 添加觀察者對象
            this.subs.push(watcher);
          }
          notify() {
            // 觸發觀察者對象的更新方法
            this.subs.forEach((watcher) => watcher.update());
          }
      }
      class Watcher {
          constructor(vm, exprOrFn) {
            this.vm = vm;
            this.deps = [];
            // 用來去重,防止多次取同一數據時存入多個相同dep
            this.depId = new Set();
            // exprOrFn是updateComponent
            this.getter = exprOrFn;
            // 更新頁面
            this.get();
          }
          get() {
            Dep.target = watcher; // 取值之前,收集 watcher
            this.getter.call(this.vm); // 調用updateComponent更新頁面
            Dep.target = null; // 取值完成后,將 watcher 刪除
          }
          // dep.depend執行時調用
          addDep(dep) {
              let id = dep.id;
              let has = this.depId.has(id);
              if (!has) {
                  this.depId.add(id);
                  // watcher存放dep
                  this.deps.push(dep);
                  // dep存放watcher
                  dep.addSub(this);
              }
          }  
          // 更新頁面方法,dep.notify執行時調用
          update() {
              this.get(); // 一修改數據就渲染更新
          }
      }
      function mountComponent(vm) {
          // 渲染更新頁面
          let updateComponent = () => {
            let vnode = vm._render(); // 生成虛擬節點 vnode
            vm._update(vnode); // 將vnode轉為真實節點
          };
          // 每個組件都要調用一個渲染 watcher
          new Watcher(vm, updateComponent);
      }
      mountComponent(vm)

       

      發布訂閱模式

      基于一個事件中心,接收通知的對象是訂閱者,需要 先訂閱某個事件,觸發事件的對象是發布者,發布者通過觸發事件,通知各個訂閱者。 js中事件綁定,就是發布訂閱模式

      發布訂閱模式相比觀察者模式多了個事件中心,訂閱者和發布者不是直接關聯的。

       

      vue中的事件總線就是使用的發布訂閱模式

      // 事件總線
      class Bus {
        constructor() {
          // 用來記錄事件和監聽該事件的數組
          this.listeners = {};
        }
        // 添加指定事件的監聽者
        $on(eventName, handler) {
          this.listeners[eventName].add(handler);
        }
        // 取消監聽事件
        $off(eventName, handler) {
          this.listeners[eventName].delete(handler);
        }
        // 觸發事件
        $emit(eventName, ...args) {
          this.listeners[eventName].forEach((fn) => fn(...args));
        }
      }

      事件總線的具體使用可以查看這篇vue之事件總線

       

      觀察者模式和發布訂閱模式的區別

      目標和觀察者之間是互相依賴的。

      發布訂閱模式是由統一的調度中心調用,發布者和訂閱者不知道對方的存在。

      博客園  ©  2004-2025
      浙公網安備 33010602011771號 浙ICP備2021040463號-3

      主站蜘蛛池模板: 无码人妻丝袜在线视频| 国产自产对白一区| 熟女女同亚洲女同中文字幕| 国产成人无码区免费内射一片色欲 | 人妻夜夜爽天天爽三区麻豆av| 加勒比无码av中文字幕| 国产免费一区二区不卡| 国产真人无遮挡免费视频| 欧美日韩国产图片区一区| 亚洲人妻精品中文字幕| 国产免费午夜福利在线播放 | 国产精品揄拍一区二区久久| 亚洲欧美人成电影在线观看| 成人影片一区免费观看| 西西人体44www大胆无码| 视频一区二区三区自拍偷拍| 噜噜综合亚洲av中文无码| 国产色视频网站免费| 国产a在视频线精品视频下载 | 人妻激情一区二区三区四区 | 国产精品99久久久久久www| 四虎国产精品永久在线| 国产精品揄拍100视频| 亚洲精品国产综合麻豆久久99 | 亚洲性人人天天夜夜摸18禁止| 亚洲 成人 无码 在线观看| 欧美特级午夜一区二区三区| 最新中文字幕国产精品| 久久精品国产成人午夜福利| 深夜视频国产在线观看| 福利一区二区1000| 一 级做人爱全视频在线看| 亚洲精品一区二区动漫| 雷波县| 亚洲人成电影网站 久久影视| 精品国产亚洲一区二区三区| 日本亚洲色大成网站www久久| 无遮挡aaaaa大片免费看| 18禁极品一区二区三区| 中文字字幕在线中文乱码| 先锋影音男人av资源|