和Java类似,JS中也有自己的设计模式,我学习的较为常用的就是:
单例模式、观察者模式、代理模式
单例模式
所谓单例模式,顾名思义就是只需创建一个全局对象,单例模式也是软件设计中较为简单但是应用最为频繁的一种模式。它的目的是保证一个类仅有一个实例,并提供一个访问它的全局访问点。他所要解决的问题是,一个全局使用的类频繁地创建与销毁。下面有几种常用的实现方式:
-
对象字面量
-
构造函数内部判断
-
闭包实现
对象字面量
let single={
name:"tom"
age:20
}
let obj1=single //浅拷贝式
let obj2=single
console.log(obj1===obj2)//true
构造函数内部判断
function single(){
if(single.protect!==undefined){
return single.protect //这一步判断的返回值就使得每次创建的对象都是一样的,实现单例
}
this.name="tom"
single.protect=this
}
let obj1=new single()
let obj2=new single()
console.log(obj1) //single {name:"tom"}
console.log(obj2) //single {name:"tom"}
console.log(obj1===obj2)//true
闭包实现
let Single = (function(){
let singleObj;
function SingleObj(){
this.name = 'tom';
//对应一个构造函数,this指向将要创建的对象,这里所有将要创建的对象都叫'tom'
}
singleObj = new SingleObj()
return function(){
return singleObj; //这里返回的singleObj就是上面构造函数新创建的
}
})();
let s1 = Single();
let s2 = Single();
console.log(s1) //singleObj {name:"tom"}
console.log(s2) //singleObj {name:"tom"}
console.log(s1 === s2)// true
观察者模式(发布-订阅)
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。现实中的例子就是,你关注的微信公众号,在更新消息时,会给每一个关注的用户推送更新的消息
观察者模式
需要用到两个参与者,发布者和订阅者
发布者对应的功能:
- 添加订阅者
- 删除订阅者
- 设置消息
- 发布消息(消息是一个私有属性,订阅者只能被动等待接收)
订阅者对应的功能:
- 接收更新的消息(被动)
// 发布者
class Publisher{
constructor(){
this.observers = []; // 订阅者名单
this.info = ''; // 准备发布的消息,私有属性,外部不能直接访问
}
// 设置消息
setInfo(val){
this.info = val;
return this;
}
// 获取消息
getInfo(){
return this.info;
}
// 添加订阅者
addObserver(obr){
let flag = true; // 默认状态:允许添加
for( let key in this.observers ){ // 遍历观察者名单
if(obr === this.observers[key]){ // 当以前的订阅者名单中已经有了当前对象
flag = false; // 设置状态不允许添加
}
}
if( flag ){ // 当状态为true才会被添加
this.observers.push(obr);
}
return this // 返回发布者
}
// 删除订阅者
removeObserver(obr){
for( let index in this.observers ){ // 遍历订阅者名单
if(this.observers[index] === obr){ // 找出订阅者名单中的对象,删除
this.observers.splice(index,1);
}
}
return this // 返回发布者
}
// 发布消息
publish(){
for( let obr of this.observers ){ // 遍历订阅者
obr.updateInfo(this.getInfo()); //订阅者获取更新消息
}
}
}
// 订阅者
class Observer{
constructor(name){
this.name = name;
}
updateInfo(info){ // 被动接收消息。(更新消息)
console.log(`我是${this.name},我现在接收的消息是:${info}`);
}
}
下面创建相应的对象并调用它们
// 创建订阅者
var ob1 = new Observer('tom');
var ob2 = new Observer('jack');
var ob3 = new Observer('alice');
// 创建发布者
var p = new Publisher();
// 添加订阅者
p.addObserver(ob1);
p.addObserver(ob2);
p.addObserver(ob3);
// 设置一条消息并发布
p.setInfo('这是第一条消息,发布者开张啦!!!').publish();
// 设置一条消息,但未发布
p.setInfo('第二条消息:大家以后想要看独家报道请冲会员啦!!!');
可以看出上面创建都是重复的操作,比较累赘,一个个手动添加也是重复的操作,会让人不满意,
这就是后期需要进行优化的地方
利用观察者模式,实现数据及时响应,写一个小案例:创建一个input框,在里面输入内容并且及时在页面中显示出来。
<input type="text" id="input">
<div id="output"></div>
function $(ele){document.querySelector(ele)}
//发布者
class publisher{
constructor(pub){
this.observes=[]
this.info=''
this.pub=pub
}
//设置消息
setInfo(){
this.info=this.pub.value
return this
}
//获取消息
getInfo(){
return this.info
}
//添加订阅者
addObserver(obr){
let flag=true
for(let index in this.abserves){
if(this.abserves[index]===obr){
flag=false
}
}
if(flag){
this.abserves.push(obr)
}
return this
}
//删除订阅者
removeObserver(obr){
for(let index in this.observes){
if(this.observes[index]===obr){
this.observes.splice(index,1)
}
}
return this
}
//发布消息
publish(){
for (let obr of this.observes){
obr.updateInfo(this.getInfo())
}
}
}
//订阅者
class Observer{
constructor(obj){
this.obj = obj;
}
// 被动接收消息。(更新消息)
updateInfo(info){
this.obj.innerText = info;
}
}
// 创建订阅者对象
var ob1 = new Observer($('#output'));
// 创建发布者对象
var p = new publisher($('#input'));
// 添加订阅者
p.addObserver(ob1);
p.pub.addEventListener('keyup',function(){ //监听函数(触发器)
p.setInfo().publish();
},false);
代理模式
为其他对象提供一种代理以控制对这个对象的访问,主要是解决直接访问可能带来的问题,在其中增加一个中间层。简单点来说,你想追个女孩子,你不好意喊她出来吃饭,你可以通过叫她的闺蜜,让她闺蜜传话
无代理模式
function Girl(name){
this.name = name;
this.receive = function(gift){
console.log('我是'+this.name+',我收到了礼物:'+gift);
}
}
function Boy(name){
this.name = name;
this.send = function(girl,gift){
console.log('我是'+this.name+',我送给'+girl.name+'礼物:'+gift);
girl.receive(gift);
};
}
let g = new Girl('翠花');
let b = new Boy('铁柱');
// 直接送礼物
b.send(g,'巧克力');
有代理模式
function Girl(name){
this.name = name;
this.receive = function(gift){
console.log('我是'+this.name+',我收到了礼物:'+gift);
}
}
function Boy(name){
this.name = name;
this.send = function(proxy,girl,gift){
console.log('我是'+this.name+',我要送给'+girl.name+'礼物:'+gift);
proxy.sendGirl(gift,this,girl);
};
}
function ProxyGirl(name){
this.name = name;
this.sendGirl = function(gift,boy,girl){
console.log(girl.name+'有人送你礼物,他的名字叫做:'+boy.name);
girl.receive(gift);
}
}
let g = new Girl('翠花');
let b = new Boy('铁柱');
let p = new ProxyGirl('红红');
b.send(p,g,'巧克力');