外观模式:为一组复杂的子系统接口提供一个更高级的统一接口,通过这个接口使得对子系统接口的访问更容易。在JavaScript中可以用于对底层结构兼容性做统一封装来简化用户的使用。
简单来说就是,提供一个接口,隐藏内部的逻辑,更加方便外部调用。
外观模式的例子:

var EventUtil={
	//外观模式
	addHandler:function(element,type,handler){
		if(element.addEventListener){
			element.addEventListener(type,handler,false);	
		}else if(element.attachEvent){
			element.attachEvent("on"+type,handler); 
		}else{
 			element["on"+type]=handler;
 		}
	},
	getEvent:function(event){
		return event?event:window.event;
	},
	getTarget:function(event){
		return event.target||event.srcElement;
	},
	preventDefault:function(){
		if(event.preventDefault){
			event.preventDefault();
		}else{
			event.returnValue=false;
		}
	},
	removeHandler:function(element,type,handler){
		if(element.removeEventListener){
			element.removeEventListener(type,handler,false);	
		}else if(element.detachEvent){
			element.detachEvent("on"+type,handler); 
		}else{
 			element["on"+type]=null;
 		}
	},
	stopPropagation:function(event){
		if(event.stopPropagation){
			event.stopPropagation();
		}else{
			event.cancelBubble=true;
		}
	}
}

适配器模式:是将一个类(对象)的接口(方法或属性)转换成客户希望的另一个接口(方法或属性),适配器模式使得原本由于接口不兼容而不能一起工作的那些类(对象)可以一起工作。
适配器模式的作用:
1.使用一个已经存在的对象,但其方法或接口不符合你的要求。
2.创建一个可复用的对象,该对象可以与其他不相关或不可见的对象协同工作。
3.使用已经存在的一个或多个对象,但不能进行继承已匹配它的接口。
注意事项:
与代理模式的区别,代理模式是不改变原接口,适配是原接口不符合规范。
适配器模式的例子:

//你原来写了一段代码比如
var dongwu={
	eat:function(){
		//some code	
	}
	sleep:function(){
		//some code	
	}
}
dongwu.eat();
//后来被别人改了
function animal(){
	this.eating=function(){
		console.log("修改代码后");	
	}
}
animal.sleeping=function(){
	console.log("你的代码我修改了");
}
//但是你还想按照你原来的方式调用,所以你就可以写一个适配器,把接口转换成你原来调用的样子
function shipeiqi(){
	var am=new animal();
	var dongwu={
		eat:function(){
			am.eating();	
		},
		sleep:function(){
			am.sleep();	
		}
	}
}
var dongwu=shipeiqi();
dongwu.eat();

代理模式(Proxy):由于一个对象不能直接引用另一个对象,所以需要通过代理对象在这两个对象之间起到中介的作用。为其他对象提供一种代理以控制对这个对象的访问。代理模式使得代理对象控制具体对象的引用。
代理模式的作用:
1.远程代理(一个对象将不同空间的对象进行局部代理)
2.虚拟代理(根据需要创建开销很大的对象如渲染网页暂时用占位代替真图)
3.安全代理(控制真实对象的访问权限)
4.智能指引(调用对象代理处理另外一些事情如垃圾回收机制)
注意事项:不能滥用代理,有时候仅仅是给代码增加复杂度
代理模式的例子:

//你要买房子,所以你找了个中介
//房东卖方
function fangdong(maijia){
	this.maijia_name=maijia.name;
	this.maifang=function(money){
		console.log(`收到来自买家${this.maijia_name}的${money}`)	
	}
}
//中介
function zhongjie(){}
zhongjie.prototype.maifang=function(){
	new fangdong(new maijia()).maifang("100000");
};
function maijia(){
	this.name="远方";
}
(new zhongjie()).maifang();

**装饰者模式:**在不改变原对象的基础上,通过对其进行包装拓展(添加属性或方法)使原有的对象可以满足用户的更复杂需求。
装饰者模式的例子:

var decorator=function(input,fn){
	//获取事件源
	var input=document.getElementById(input);
	if(typeof input.onclick==='function'){
		//缓存事件源原有回调函数
		var oldClickFn=input.onclick;
		input.onclick=function(){
			oldClickFn();
			//执行事件源定义新的事件
			fn();
		}	
	}else{
		input.onclick=fn;
	}
}

桥接模式:在系统沿着多个维度变化的同时,又不增加其复杂度并已达到解耦。将抽象部分与它的实现部分分离,使他们都可以独立地变化。
桥接模式的例子:

var divs=document.getElementsByTagName("div");
divs[0].onmouseover=function(){
	this.style.color="pink";
	this.style.background="#aaa";
};
divs[0].onmouseout=function(){
	this.style.color="red";
	this.style.background="#666";
};
divs[1].onmouseover=function(){
	this.getElementsByTagName("i")[0].style.color="pink";
	this.getElementsByTagName("i")[0].style.background="#aaa";
};
divs[1].onmouseout=function(){
	this.getElementsByTagName("i")[0].style.color="red";
	this.getElementsByTagName("i")[0].style.background="#666";
};
...
//提取共有的部分
function changeStyle(element,color,bg){
	element.style.color=color;
	element.style.background=bg;
}
var divs=document.getElementsByTagName("div");
divs[0].onmouseover=function(){
	changeStyle(this,"pink","#aaa");
};
divs[0].onmouseout=function(){
	changeStyle(this,"red","#666");
};
divs[1].onmouseover=function(){
	changeStyle(this.getElementsByTagName("i")[0],"pink","#aaa");
};
divs[1].onmouseout=function(){
	changeStyle(this.getElementsByTagName("i")[0],"red","#666");
};
...

**组合模式:**又称部分-整体模式,将对象组合成树形结构,以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
组合模式的主要的三个角色:
(1)抽象组件:抽象类,主要定义了参与组合的对象的公共接口
(2)子对象:组合对象的最基本的对象
(3)组合对象:由子对象组合起来的复杂对象
享元模式:运用共享的技术有效地支持大量的细粒度的对象,避免对象间拥有相同内容造成多余的开销。
享元模式例子:

var Fly={
	moveX=function(x){
		this.x=x;	
	},
	moveY=function(y){
		this.y=y;	
	}
}
var Plane=function(x,y,score){
	this.x=x;
	this.y=y;
	this.score=score;
}
Plane.prototype=Fly;
Plane.prototype.getScore=function(score){
	this.score=score;
}
var f16=new Plane(7,8,90);
console.log(f16);
f16.moveX(8);
f16.moveX(9);
f16.getScore(95);
console.log(f16);