JS设计模式发布订阅模式:这种设计模式可以大大降低程序模块之间的耦合度,方便更灵活的扩展和维护。//播放器类classPlayer{constructor(){//初始化观察者列表this.watchers={}//模拟2秒后发布'play'事件setTimeout(()=>{this._publish('play',true)},2000)//在模拟4秒后发布一个'pause'事件setTimeout(()=>{this._publish('pause',true)},4000)}//发布事件_publish(event,data){if(this.watchers[event]&&this.watchers[event].length){this.watchers[event].forEach(callback=>callback.bind(this)(data))}}//订阅事件订阅(事件,回调){this.watchers[event]=this.watchers[event]||[]this.watchers[event].push(callback)}//取消订阅事件unsubscribe(event=null,callback=null){//如果传入指定的事件函数,则只取消订阅这个事件函数if(callback&&event){if(this.watchers[event]&&this.watchers[event].length){this.watchers[event].splice(this.watchers[event].findIndex(cb=>Object.is(cb,callback)),1)}//如果只传入事件名,取消订阅该事件对应的所有事件函数}elseif(事件){this.watchers[event]=[]//如果没有传入参数,取消订阅所有事件}else{this.watchers={}}}}//实例化播放器constplayer=newPlayer()console.log(player)//播放事件回调函数1constonPlayerPlay1=function(data){console.log('1:Playerisplay,the`this`contextiscurrentplayer',this,data)}//播放事件回调函数2constonPlayerPlay2=data=>{console.log('2:Playerisplay',data)}//暂停事件回调函数constonPlayerPause=data=>{console.log('Playerispause',data)}//加载事件回调函数constonPlayerLoaded=data=>{console.log('Playerisloaded',data)}//可以订阅多个不同的事件player.subscribe('play',onPlayerPlay1)player.subscribe('play',onPlayerPlay2)player.subscribe('pause',onPlayerPause)player.subscribe('loaded',onPlayerLoaded)//可以取消订阅指定的订阅事件player.unsubscribe('play',onPlayerPlay2)//取消订阅指定事件名player下的所有订阅事件.unsubscribe('play')//取消订阅所有订阅事件player.unsubscribe()//事件可以手动对外发布(实际生产场景下,发布功能一般是类内部的私有方法)player._publish('loaded',true)中介者模式:观察者模式通过维护一堆列表来管理对象之间的多对多关系。中介者模式通常通过统一的接口维护一对多关系,通信者不需要知道彼此之间的关系,只需要约定API//CarclassBus{constructor(){//初始化所有乘客this.passengers={}}//发布广播broadcast(passenger,message=passenger){//如果公交车上有乘客if(Object.keys(this.passenger).length){//如果是某位乘客,让他单独听if(passenger.id&&passenger.listen){//乘客是否愿意听if(this.passengers[passenger.id]){this.passengers[passenger.id].listen(message)}//否则广播给所有乘客}else{Object.keys(this.passengers).forEach(passenger=>{if(this.passengers[passenger].listen){this.passengers[passenger].listen(message)}})}}}//乘客登机aboard(passenger){this.passengers[passenger.id]=passenger}//乘客下车debus(passenger){this.passengers[passenger.id]=nulldeletethis.passengers[passenger.id]console.log(`passenger${passenger.id}getoff`)}//drivestart(){this.broadcast({type:1,content:'前方无障碍,开车!Over'})}//停车end(){this.broadcast({type:2,content:'老司机翻车了,停!over'})}}//乘客类Passenger{constructor(id){this.id=id}//听广播listen(message){安慰。log(`Passenger${this.id}receivedamessage`,message)//乘客发现车停好了,于是下车if(Object.is(message.type,2)){this.debus()}}//下车debus(){console.log(`我是乘客${this.id},我要下车`,bus)bus.debus(this)}}//创建一辆车constbus=newBus()//创建两个乘客constpassenger1=newPassenger(1)constpassenger2=newPassenger(2)//两个乘客分别上车bus.aboard(passenger1)bus.aboard(passenger2)//Driveafter2secondssetTimeout(bus.start.bind(bus),2000)//3秒后,司机发现乘客2没有买票,乘客2被驱逐下车。setTimeout(()=>{bus.broadcast(passenger2,{type:3,content:'同志您好,您没有买票,请下车!'})bus.debus(passenger2)},3000)//4秒后到站setTimeout(bus.end.bind(bus),3600)//6秒后行驶,车内没有乘客setTimeout(bus.start.bind(bus),6666)代理模式:为其他对象提供一个代理来控制对这个对象的访问代理模式使代理对象能够控制对特定对象的引用。代理几乎可以是任何对象:文件、资源、内存中的对象或难以复制的对象。ES6中的代理对象consttarget={}consthandler={get(target,property){if(propertyintarget){returntarget[property]}else{thrownewReferenceError("Property\""+property+"\"不存在。")}}}constp=newProxy(target,{})p.a=3//操作转发给代理console.log(p.c)//单例模式:保证一个类只有一个实例,并提供一个全局访问点来访问它(调用一个类,任何时候返回的都是同一个实例)。实现方法:用一个变量来标记是否为某个类创建了对象。如果创建了,则下次获取该类的实例时,直接返回之前创建的对象,否则创建一个对象。//类数实例:classSingleton{constructor(name){this.name=namethis.instance=null//}getName(){alert(this.name)}staticgetInstance(name){if(!this.instance){this.instance=newSingleton(name)}returnthis.instance}}constins=newSingleton('hhhh')constinstanceA=Singleton.getInstance('seven1')constinstanceB=Singleton.getInstance('seven2')//闭包实例:constSingletonP=(function(){letinstancereturnclassSingleton{constructor(name){if(instance){returninstance}else{this.init(name)instance=thisreturnthis}}init(name){this.name=nameconsole.log('已初化')}}})()constinstanceA=newSingletonP('seven1')constinstanceB=newSingletonP('seven2')//ES5iifevarSingletonTester=(function(){functionSingleton(args){varargs=args||{};//设置名称参数this.name='SingletonTester';}//实例容器varinstance;返回{name:'SingletonTester',getInstance:function(args){if(instance===undefined){instance=newSingleton(args);}返回实例;}};})();varsingletonTest=SingletonTester.getInstance({pointX:5});console.log(singletonTest.pointX);//输出5//构造函数Universe()的属性{if(typeofUniverse.instance==='object'){returnUniverse.instance;}this.start_time=0;this.bang="大";Universe.instance=this;}//测试varuni=newUniverse();varuni2=newUniverse();console.log(uni===uni2);//true//覆盖构造函数Universe(){varinstance=this;//其他内容this.start_time=0;this.bang="大";//重写构造函数Universe=function(){returninstance;};}//测试varuni=newUniverse();varuni2=newUniverse();uni.bang="123";console.log(uni===uni2);//trueconsole.log(uni2.bang);//123FactoryPattern工厂模式:工厂模式定义了一个用于创建对象的接口。这个接口由子类决定实例化哪个类。这种模式将类的实例化延迟到子类。子类在创建它们时可以重写接口方法来指定它们自己的对象类型。简单的说:如果我们要在网页中插入一些元素,而这些元素的类型是不固定的,可能是图片,链接,文本,根据工厂模式的定义,在工厂模式下,工厂函数只需要接受我们想要创建类型的元素,其他工厂函数为我们处理它。//文档工厂classText{constructor(text){this.text=text}insert(where){consttxt=document.createTextNode(this.text)where.appendChild(txt)}}//链接工厂classLink{constructor(url){this.url=url}insert(where){constlink=document.createElement('a')link.href=this.urllink.appendChild(document.createTextNode(this.url))where.appendChild(link)}}//图片工厂classImage{constructor(url){this.url=url}insert(where){constimg=document.createElement('img')img.src=this.urlwhere.appendChild(img)}}//DOM工厂classDomFactory{constructor(type){returnnew(this[type]())}//各流水线link(){returnLink}text(){returnText}image(){returnImage}}//创建工厂constlinkFactory=newDomFactory('link')consttextFactory=newDomFactory('text')linkFactory.url='https://surmon.me'linkFactory.insert(document.body)textFactory.text='嗨!我是surmon.'textFactory.insert(document.body)装饰器模式DecorativePattern:装饰器(decorator)模式可以在程序运行过程中赋予对象而不改变对象本身。与继承相比,装饰器是一种更轻便、更灵活的动态添加职责(方法或属性)的方式。简单地说:您可以动态地为一个对象添加额外的职责,而不会影响从该类派生的其他对象。ES7装饰器函数isAnimal(target){target.isAnimal=truereturntarget}//decorator@isAnimalclassCat{//...}console.log(Cat.isAnimal)//类属性的真正装饰器:functionreadonly(target,名称,描述符){discriptor.writable=falsereturndiscriptor}classCat{@readonlysay(){console.log("meow~")}}varkitty=newCat()kitty.say=function(){console.log("woof!")}kitty.say()//喵~参考:输入理解js系列自ES6入门练习
