JavaScript实现单例模式

Linux大全评论497 views阅读模式

传统单例模式

  保证一个类仅有一个实例,并提供一个访问它的全局访问点。

实现单例核心思想

  无非是用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象,接下来我们用JavaScript来强行实现这个思路,请看代码:

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)嘛!

  最后贴一个高度抽象的单例模式代码,惰性单例的精髓!!

    //单例模式抽象,分离创建对象的函数和判断对象是否已经创建
    var getSingle = function (fn) {
        var result;
        return function () {
            return result || ( result = fn.apply(this, arguments) );
        }
    };

  形参fn是我们的构造函数,我们只要传入任何自己需要的构造函数,就能生成一个新的惰性单例。比如说传入创建一个女朋友的构造函数,并且调用getSingle(),就能生成一个新的女朋友。如果以后再调getSingle(),也只会返回刚才创建的那个女朋友。至于新女朋友——不存在的。

单例常用场景

企鹅博客
  • 本文由 发表于 2019年9月3日 05:16:56
  • 转载请务必保留本文链接:https://www.qieseo.com/136232.html

发表评论