1. 定义
观察者模式 一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
2.作用 促进形成松散耦合
3.相关实例代码
普通对象实现
var subject0=function(){ console.log('subject0'); } var subject1=function(){ console.log('subject1'); } var observer={ callbacks:[], add:function(subject){ this.callbacks.push(subject) }, publish:function(){ this.callbacks.forEach(function(item){ item() }) } } observer.add(subject0); observer.add(subject1); observer.publish();
class 方式实现
var subject0=function(){ console.log('subject0'); } var subject1=function(){ console.log('subject1'); } class Observer{ constructor(){ this.subjects=[] } add(subject){ this.subjects.push(subject) } publish(){ this.subjects.forEach(function(item){ item() }) } } var observer1=new Observer() observer1.add(subject0); observer1.add(subject1); observer1.publish();
改造 ajax 实例 前
$.ajax({ url: "test.html", context: document.body }).done(function(data) { //data数据的处理 $('aaron1').html(data.a) $('aaron2').html(data.b) $('aaron3').html(data.c) //其余处理 });
改造 ajax 实例 后
Observable.add(function() { //pocessData }) Observable.add(function() { $('aaron1').html(data.a) $('aaron2').html(data.b) $('aaron3').html(data.c) }) Observable.add(function() { //pocessOther }) $.ajax({ url: "test.html", context: document.body }).done(function(data) { Observable.fire(data) })
带参数与链式调用
class Observer{ constructor(){ this.callbacks=[] } on(name){ this.callbacks.push(name) return this } emit(...args){ this.callbacks.forEach(item=>{ item.apply(null,args) }) return this } off(name){ this.callbacks.forEach((item,key)=>{ if(item===name){ this.callbacks.splice(key,1) } }) return this } } var observer=new Observer(); var subject1=function(){ console.log('subject1') } var subject2=function(...args){ console.log(args.join(' ')) } observer.on(subject1).on(subject2).off(subject1).emit('1','2','3')
lass PubSub { constructor() { this.handles = {}; } on(eventType, handle) { if (!this.handles.hasOwnProperty(eventType)) { this.handles[eventType] = []; } if (typeof handle == 'function') { this.handles[eventType].push(handle); } else { throw new Error('缺少回调函数'); } return this; } emit(eventType, ...args) { if (this.handles.hasOwnProperty(eventType)) { this.handles[eventType].forEach((item, key, arr) => { item.apply(null, args); }) } else { throw new Error(`"${eventType}"事件未注册`); } return this; } off(eventType, handle) { if (!this.handles.hasOwnProperty(eventType)) { throw new Error(`"${eventType}"事件未注册`); } else if (typeof handle != 'function') { throw new Error('缺少回调函数'); } else { this.handles[eventType].forEach((item, key, arr) => { if (item == handle) { arr.splice(key, 1); } }) } return this; // 实现链式操作 } } let callback = function () { console.log('you are so nice'); } let pubsub = new PubSub(); pubsub.on('namespace', (...args) => { console.log(args.join(' ')); }).on('namespace', callback); pubsub.emit('namespace', '1', '2', '3'); pubsub.off('namespace', callback); pubsub.emit('namespace', '1', '2');
传统写法
function Public() { this.handlers = {}; } Public.prototype = { on: function(eventType, handler){ var self = this; if(!(eventType in self.handlers)) { self.handlers[eventType] = []; } self.handlers[eventType].push(handler); return this; }, emit: function(eventType){ var self = this; var handlerArgs = Array.prototype.slice.call(arguments,1); for(var i = 0; i < self.handlers[eventType].length; i++) { self.handlers[eventType][i].apply(self,handlerArgs); } return self; }, off: function(eventType, handler){ var currentEvent = this.handlers[eventType]; var len = 0; if (currentEvent) { len = currentEvent.length; for (var i = len - 1; i >= 0; i--){ if (currentEvent[i] === handler){ currentEvent.splice(i, 1); } } } return this; } }; var Publisher = new Public(); Publisher.on('a', function(data){ console.log(1 + data); }); Publisher.on('a', function(data){ console.log(2 + data); }); Publisher.emit('a', '我是第1次调用的参数'); Publisher.emit('a', '我是第2次调用的参数');
4. 其他扩展
4.1 单例模式
var getSingle = function(fn){ var result; return function(){ return result || (result = fn.apply(this, arguments)); } }; var createDiv = function(){ var div = document.createElement('div'); div.style.width = '100px'; div.style.height = '100px'; div.style.background = 'red'; div.style.marginBottom = '10px'; document.body.appendChild(div); return div; }; var createSingleDiv = getSingle(createDiv); createSingleDiv(); createSingleDiv(); createSingleDiv();