传统单例模式html
保证一个类仅有一个实例,并提供一个访问它的全局访问点。编程
实现单例核心思想闭包
无非是用一个变量来标志当前是否已经为某个类建立过对象,若是是,则在下一次获取该类的实例时,直接返回以前建立的对象,接下来咱们用JavaScript来强行实现这个思路,请看代码:app
var Singleton = function( name ){ this.name = name; };
Singleton.prototype.getName = function(){
alert ( this.name ); };
Singleton.getInstance = (function(){
var instance = null;
return function( name ){ if ( !instance ){ instance = new Singleton( name ); } return instance;
} })();
咱们经过Singleton.getInstance来获取Singleton类的惟一对象,这样确实是没问题的,可是js自己是没有类这种概念的,因此咱们强行用传统单例思想来实现是没有任何意义的,这样的代码又臭又长(实际上是我本身看着不舒服嘻嘻嘻)。下面咱们使用JavaScript的闭包来实现一个单例,请看代码:函数
var CreateDiv = (function(){
var instance; var CreateDiv = function( html ){
if ( instance ){ return instance;
} this.html = html; this.init(); return instance = this; }; CreateDiv.prototype.init = function(){ var div = document.createElement( 'div' );
div.innerHTML = this.html;
document.body.appendChild( div ); }; return CreateDiv;
})();
var a = new CreateDiv( 'sven1' );
var b = new CreateDiv( 'sven2' ); alert ( a === b ); // true
能够看到,这样咱们确实用闭包来实现了一个单例,但这个代码仍是高度耦合的,CreateDiv的构造函数实际上负责了两件事情。第一是建立对象和执行初始化init方法,第二是保证只有一个对象。这样的代码是职责不明确的,如今咱们要把这两个工做分开,构造函数就负责构建对象,至于判断是返回现有对象仍是构造新的对象并返回,咱们交给另一个函数去完成,其实也就是为了知足一个编程思想:单一职责原则。这样的代码才能更好的解耦,请看下面代码:性能
var CreateDiv = function (html) { this.html = html; this.init(); }; CreateDiv.prototype.init = function () { var div = document.createElement('div'); div.innerHTML = this.html; document.body.appendChild(div); }; var ProxySingletonCreateDiv = (function () { var instance; return function (html) { if (!instance) { instance = new CreateDiv(html); } return instance; } })(); var a = new ProxySingletonCreateDiv('sven1'); var b = new ProxySingletonCreateDiv('sven2'); alert(a === b); //true
能够看到,如今咱们的构造函数CreateDiv如今只负责构造对象,至因而返回现有对象仍是构造新的对象并返回,这件事咱们交给了代理类proxySingletonCreateDiv来处理,这样的代码看着才舒(zhuang)服(bi)嘛!this
最后贴一个高度抽象的单例模式代码,惰性单例的精髓!!:spa
//单例模式抽象,分离建立对象的函数和判断对象是否已经建立 var getSingle = function (fn) { var result; return function () { return result || ( result = fn.apply(this, arguments) ); } };
形参fn是咱们的构造函数,咱们只要传入任何本身须要的构造函数,就能生成一个新的惰性单例。好比说传入建立一个女友的构造函数,而且调用getSingle(),就能生成一个新的女友。若是之后再调getSingle(),也只会返回刚才建立的那个女友。至于新女友——不存在的。prototype
单例经常使用场景代理
只须要生成一个惟一对象的时候,好比说页面登陆框,只可能有一个登陆框,那么你就能够用单例的思想去实现他,固然你不用单例的思想实现也行,那带来的结果可能就是你每次要显示登录框的时候都要从新生成一个登录框并显示(耗费性能),或者是不当心显示出了两个登陆框(等着吃经理的40米长刀吧),嘻嘻嘻。