中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JS中自定義事件與觀察者模式實例分析

發布時間:2022-07-01 10:12:31 來源:億速云 閱讀:130 作者:iii 欄目:開發技術

這篇文章主要介紹了JS中自定義事件與觀察者模式實例分析的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇JS中自定義事件與觀察者模式實例分析文章都會有所收獲,下面我們一起來看看吧。

一、前言

觀察者模式 也稱發布-訂閱模式 、 模型-視圖模式 。當對象間存在一對多關系時,則使用觀察者模式(Observer Pattern)。比如,當一個對象被修改時,則會自動通知依賴它的對象。觀察者模式屬于行為型模式。

觀察者模式: 類似我們在微信平臺訂閱了公眾號 , 當它有新的文章發表后,就會推送給我們所有訂閱的人。

我們作為訂閱者不必每次都去查看這個公眾號有沒有新文章發布,公眾號作為發布者會在合適時間通知我們。

我們與公眾號之間不再強耦合在一起。公眾號不關心誰訂閱了它, 不管你是男是女還是寵物狗,它只需要定時向所有訂閱者發布消息即可。

二、觀察者模式優缺點

優點:

  • 可以廣泛應用于異步編程,它可以代替我們傳統的回調函數。

  • 我們不需要關注對象在異步執行階段的內部狀態,我們只關心事件完成的時間點。

  • 取代對象之間硬編碼通知機制,一個對象不必顯式調用另一個對象的接口,而是松耦合的聯系在一起。

  • 降低了目標與觀察者之間的耦合關系,兩者之間是抽象耦合關系。符合依賴倒置原則。

缺點:

  • 如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。

  • 如果在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發它們之間進行循環調用,可能導致系統崩潰。

  • 觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎么發生變化的,而僅僅只是知道觀察目標發生了變化。

三、代碼實現

  • Event簡易版

var Event = (function() {
  let list = {};
  let listen = function(key, fn) {
    (list[key] || (list[key] = [])).push(fn);
  };
  let remove = function(key, fn) {
    let fns = list[key];
    if (!fns) return;
    if (!fn) {
      fns && (fns.length = 0);
    } else {
      for (let i = fns.length - 1; i >= 0; i--) {
        fns[i] === fn && (fns.splice(i, 1));
      }
    }
  };
  let trigger = function() {
    let keys = [].shift.call(arguments);
    let fns = list[keys];
    if (!fns || fns.length === 0) return;
    for (let i = 0, fn; fn = fns[i++];) {
      fn.apply(this, arguments);
    }
  };
  return {
    listen,
    remove,
    trigger
  };
})();
// 使用
function log(name) {
  console.log(name)
}
Event.listen('to-do', log)    // 訂閱事件
Event.trigger('to-do', '111') // 111
Event.trigger('to-do', '222') // 222
Event.remove('to-do', log)    // 移除事件
Event.trigger('to-do', '333') // 不執行
  • 類似Nodejs的EventEmitter模擬版

function EventEmitter() {
  this._maxListeners = 10;
  this._events = Object.create(null);
}
// 向事件隊列添加事件
// prepend為true表示向事件隊列頭部添加事件
EventEmitter.prototype.addListener = function (type, listener, prepend) {
  if (!this._events) {
    this._events = Object.create(null);
  }
  if (this._events[type]) {
    if (prepend) {
      this._events[type].unshift(listener);
    } else {
      this._events[type].push(listener);
    }
  } else {
    this._events[type] = [listener];
  }
};
// 移除某個事件
EventEmitter.prototype.removeListener = function (type, listener) {
  if (Array.isArray(this._events[type])) {
    if (!listener) {
      delete this._events[type]
    } else {
      this._events[type] = this._events[type].filter(e => e !== listener && e.origin !== listener)
    }
  }
};
// 向事件隊列添加事件,只執行一次
EventEmitter.prototype.once = function (type, listener) {
  const only = (...args) => {
    listener.apply(this, args);
    this.removeListener(type, listener);
  }
  only.origin = listener;
  this.addListener(type, only);
};
// 執行某類事件
EventEmitter.prototype.emit = function (type, ...args) {
  if (Array.isArray(this._events[type])) {
    this._events[type].forEach(fn => {
      fn.apply(this, args);
    });
  }
};
// 設置最大事件監聽個數
EventEmitter.prototype.setMaxListeners = function (count) {
  this.maxListeners = count;
};
// 使用
var emitter = new EventEmitter();
var onceListener = function (args) {
  console.log('我只能被執行一次', args, this);
}
var listener = function (args) {
  console.log('我是一個listener', args, this);
}
emitter.once('click', onceListener);
emitter.addListener('click', listener);
emitter.emit('click', '參數');
emitter.emit('click');
emitter.removeListener('click', listener);
emitter.emit('click');

四、DOM自定義事件API

  • Event構造器

// 創建
var customEvent = new Event('custom-event');
// 監聽
window.addEventListener('custom-event', function(e) {
  // do something ...
  console.log(`事件對象:`, e)
})
// 觸發
window.dispatchEvent(customEvent)
  • CustomEvent構造器,可傳遞參數。

// 創建
var customEvent = new CustomEvent('custom-event', {
  data: {
    name: 'Tom',
    age: 18,
    other: 'otherMessage',
  }
});
// 監聽
var eBox = document.getElementById('box')
eBox.addEventListener('custom-event', function(e) {
  // do something ...
  console.log(`傳入的數據:`, e.data)
})
// 觸發 兼容寫法
if(window.dispatchEvent) {
  eBox.dispatchEvent(customEvent);
} else {
  // IE8
  eBox.fireEvent(customEvent);
}

關于“JS中自定義事件與觀察者模式實例分析”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“JS中自定義事件與觀察者模式實例分析”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

js
AI

邵阳市| 道真| 蛟河市| 湖北省| 乌鲁木齐县| 泽库县| 乳山市| 宝鸡市| 建平县| 将乐县| 墨竹工卡县| 安义县| 沁阳市| 峨眉山市| 砚山县| 广西| 承德县| 普陀区| 霸州市| 安西县| 察隅县| 汕头市| 隆回县| 余姚市| 秀山| 宜宾市| 古丈县| 大石桥市| 杂多县| 奉化市| 高台县| 汪清县| 昭觉县| 右玉县| 伊川县| 轮台县| 宝山区| 益阳市| 伊宁县| 元氏县| 浮山县|