亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JS中自定義事件與觀察者模式詳解

 更新時(shí)間:2022年06月30日 14:20:22   作者:天問(wèn)  
這篇文章主要為大家介紹了JS中自定義事件與觀察者模式的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

一、前言

觀察者模式 也稱(chēng)發(fā)布-訂閱模式 、 模型-視圖模式 。當(dāng)對(duì)象間存在一對(duì)多關(guān)系時(shí),則使用觀察者模式(Observer Pattern)。比如,當(dāng)一個(gè)對(duì)象被修改時(shí),則會(huì)自動(dòng)通知依賴(lài)它的對(duì)象。觀察者模式屬于行為型模式。

觀察者模式: 類(lèi)似我們?cè)谖⑿牌脚_(tái)訂閱了公眾號(hào) , 當(dāng)它有新的文章發(fā)表后,就會(huì)推送給我們所有訂閱的人。

我們作為訂閱者不必每次都去查看這個(gè)公眾號(hào)有沒(méi)有新文章發(fā)布,公眾號(hào)作為發(fā)布者會(huì)在合適時(shí)間通知我們。

我們與公眾號(hào)之間不再?gòu)?qiáng)耦合在一起。公眾號(hào)不關(guān)心誰(shuí)訂閱了它, 不管你是男是女還是寵物狗,它只需要定時(shí)向所有訂閱者發(fā)布消息即可。

二、觀察者模式優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  • 可以廣泛應(yīng)用于異步編程,它可以代替我們傳統(tǒng)的回調(diào)函數(shù)。
  • 我們不需要關(guān)注對(duì)象在異步執(zhí)行階段的內(nèi)部狀態(tài),我們只關(guān)心事件完成的時(shí)間點(diǎn)。
  • 取代對(duì)象之間硬編碼通知機(jī)制,一個(gè)對(duì)象不必顯式調(diào)用另一個(gè)對(duì)象的接口,而是松耦合的聯(lián)系在一起。
  • 降低了目標(biāo)與觀察者之間的耦合關(guān)系,兩者之間是抽象耦合關(guān)系。符合依賴(lài)倒置原則。

缺點(diǎn):

  • 如果一個(gè)被觀察者對(duì)象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間。
  • 如果在觀察者和觀察目標(biāo)之間有循環(huán)依賴(lài)的話,觀察目標(biāo)會(huì)觸發(fā)它們之間進(jìn)行循環(huán)調(diào)用,可能導(dǎo)致系統(tǒng)崩潰。
  • 觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對(duì)象是怎么發(fā)生變化的,而僅僅只是知道觀察目標(biāo)發(fā)生了變化。

三、代碼實(shí)現(xiàn)

  • Event簡(jiǎn)易版
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') // 不執(zhí)行
  • 類(lèi)似Nodejs的EventEmitter模擬版
function EventEmitter() {
  this._maxListeners = 10;
  this._events = Object.create(null);
}
// 向事件隊(duì)列添加事件
// prepend為true表示向事件隊(duì)列頭部添加事件
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];
  }
};
// 移除某個(gè)事件
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)
    }
  }
};
// 向事件隊(duì)列添加事件,只執(zhí)行一次
EventEmitter.prototype.once = function (type, listener) {
  const only = (...args) => {
    listener.apply(this, args);
    this.removeListener(type, listener);
  }
  only.origin = listener;
  this.addListener(type, only);
};
// 執(zhí)行某類(lèi)事件
EventEmitter.prototype.emit = function (type, ...args) {
  if (Array.isArray(this._events[type])) {
    this._events[type].forEach(fn => {
      fn.apply(this, args);
    });
  }
};
// 設(shè)置最大事件監(jiān)聽(tīng)個(gè)數(shù)
EventEmitter.prototype.setMaxListeners = function (count) {
  this.maxListeners = count;
};
// 使用
var emitter = new EventEmitter();
var onceListener = function (args) {
  console.log('我只能被執(zhí)行一次', args, this);
}
var listener = function (args) {
  console.log('我是一個(gè)listener', args, this);
}
emitter.once('click', onceListener);
emitter.addListener('click', listener);
emitter.emit('click', '參數(shù)');
emitter.emit('click');
emitter.removeListener('click', listener);
emitter.emit('click');

四、DOM自定義事件API

  • Event構(gòu)造器
// 創(chuàng)建
var customEvent = new Event('custom-event');
// 監(jiān)聽(tīng)
window.addEventListener('custom-event', function(e) {
  // do something ...
  console.log(`事件對(duì)象:`, e)
})
// 觸發(fā)
window.dispatchEvent(customEvent)
  • CustomEvent構(gòu)造器,可傳遞參數(shù)。
// 創(chuàng)建
var customEvent = new CustomEvent('custom-event', {
  data: {
    name: 'Tom',
    age: 18,
    other: 'otherMessage',
  }
});
// 監(jiān)聽(tīng)
var eBox = document.getElementById('box')
eBox.addEventListener('custom-event', function(e) {
  // do something ...
  console.log(`傳入的數(shù)據(jù):`, e.data)
})
// 觸發(fā) 兼容寫(xiě)法
if(window.dispatchEvent) {
  eBox.dispatchEvent(customEvent);
} else {
  // IE8
  eBox.fireEvent(customEvent);
}

以上就是JS中自定義事件與觀察者模式詳解的詳細(xì)內(nèi)容,更多關(guān)于JS自定義事件觀察者模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論