单例模式也称为单体模式,规定一个类只有一个实例,而且提供可全局访问点;html
在读这篇文章以前,也许你对单例模式的概念感到模糊或者不清楚,可是其实在平常的开发中你确定用到过单例模式;闭包
JavaScript中没有类的定义,单例模式的特色是”惟一“和”全局访问“,那么咱们能够联想到JavaScript中的全局对象,利用ES6的let不容许重复声明的特性,恰好符合这两个特色;是的,全局对象是最简单的单例模式;app
let obj = { name:"咸鱼", getName:function(){} }
上述代码中能够知道obj就是一个单例,由于obj恰好就符合单例模式的两大特色:"惟一"和"可全局访问";性能
可是咱们并不建议这么实现单例,由于全局对象/全局变量会有一些弊端:学习
简单版单例模式:ui
分析:只能有一个实例,因此咱们须要使用if分支来判断,若是已经存在就直接返回,若是不存在就新建一个实例;this
let Singleton = function(name){ this.name = name; this.instance = null; } Singleton.prototype.getName = function(){ console.log(this.name); } Singleton.getInstance = function(name){ if(this.instace){ return this.instance; } return this.instance = new Singleton(name); } let winner = Singleton.getInstance("winner"); //winner console.log(winner.getName()); let sunner = Singleton.getInstance("sunner"); //winner console.log(sunner.getName())
上面代码中咱们是经过一个变量instance的值来进行判断是否已存在实例,若是存在就直接返回this.instance,若是不存在,就新建实例并赋值给instance;spa
可是上面的代码仍是存在问题,由于建立对象的操做和判断实例的操做耦合在一块儿,并不符合”单一职责原则“;prototype
改良版:代理
思路:经过一个闭包,来实现判断实例的操做;
闭包警告:不理解闭包的同窗请先学习闭包 http://www.javashuo.com/article/p-cgfnevvn-gm.html
let CreateSingleton = (function(){ let instance = null; return function(name){ this.name = name; if(instance){ return instance } return instance = this; } })() CreateSingleton.prototype.getName = function(){ console.log(this.name); } let winner = new CreateSingleton("winner"); //winner console.log(winner.getName()); let sunner = new CreateSingleton("sunner"); //winner console.log(sunner.getName())
代理版单例模式:
经过代理的形式,将建立对象的操做和实例判断的操做进行解耦拆分,实现更小粒度的划分,符合”单一职责原则“;
let ProxyCreateSingleton = (function(){ let instance = null; return function(name){ if(instance){ return instance } return instance = new Singlton(name); } })(); let Singlton = function(name){ this.name = name; } Singlton.prototype.getName = function(){ console.log(this.name); } let winner = new ProxyCreateSingleton("winner"); console.log(winner.getName()); let sunner = new ProxyCreateSingleton("sunner"); console.log(sunner.getName());
上面的代码中,ProxyCreateSingleton()只负责判断实例,Singlton只负责建立对象和赋值;
惰性单例模式
咱们常常会有这样的场景:页面屡次调用都有弹窗提示,只是提示内容不同;
这个时候咱们能够立马想到是单例模式,弹窗就是单例实例,提示内容是参数传递;咱们能够用惰性单例模式来实现它;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="loginBtn">有梦想的咸鱼</div> </body> <script> let getSingleton = function(fn) { var result; return function() { return result || (result = fn.apply(this, arguments)); // 肯定this上下文并传递参数 } } let createAlertMessage = function(html) { var div = document.createElement('div'); div.innerHTML = html; div.style.display = 'none'; document.body.appendChild(div); return div; } let createSingleAlertMessage = getSingleton(createAlertMessage); document.getElementById('loginBtn').onclick=function(){ let alertMessage = createSingleAlertMessage('看来真的是个咸鱼'); alertMessage.style.display = 'block'; } </script> </html>
惰性单例是指的是页面开始加载的时候咱们的实例是没有进行建立的,是当咱们点击页面的div以后才开始建立实例(按需建立),这能够提升咱们的网页性能,加快咱们的页面渲染速度;