JS设计模式——单例模式剖析

转载于原文地址:https://blog.csdn.net/q1056843325/article/details/52933426缓存

举一个通俗的例子,在页面中点击登陆按钮,弹出了一个登陆浮窗,这个登陆浮窗是惟一的,不管咱们单击多少次,浮窗只会建立一次。闭包

其实咱们可能无心中都会使用过单例模式,咱们的作法每每都是使用一个变量来标志当前是否已经为某个类建立了对象, 若是true,那么下一次再想得到这个类的实例时,直接返回以前建立过的对象。app

单例模式的核心是确保只有一个实例,并提供全局访问。函数

 

其实在JavaScript中,单例模式并无这么复杂 
this

var a = {};

咱们这样建立了对象a,它确实独一无二 
并且知足了单例模式的两个条件spa

  • 一个实例
  • 全局访问

可是全局变量很容易形成命名空间污染 ,若是项目很大的话,不当心覆盖了变量那就是致命的。.net

因此,在详细讲解这个单例模式以前,咱们先来讨论这样一个问题,怎样下降全局污染? (全局污染也就是变量大量存在于全局做用域污染了全局空间 )code

下降全局污染有两种办法:对象

一、使用命名空间

var namespace_payen = {
    a: function(){
        //...
    }
    b: function(){
        //...
    }
}

适当使用命名空间,并不会杜绝全局变量,可是能够减小全局变量的数量blog

二、使用闭包封装私有变量

var payen = (function(){
    var _name = 'payson.Tsung',
        _age = 19;
    return {
        getInfo: function(){
            return _name + ' ' + _age;
        }
    }
})();

变量被封装在了闭包内,只暴露一些接口用于外部通讯,从而避免了对全局的命令污染

 

下面我来谈谈这个单例模式 

先来个简单的例子 

下面我声明了一个函数,每次调用都建立一个小方块

function createDiv(){
    var div = document.createElement('div');
    div.style.width = '100px';
    div.style.height = '100px';
    div.style.background = 'red';
    div.style.marginBottom = '10px';
    document.body.appendChild(div);
}
createDiv();
createDiv();
createDiv();

调用了三次,页面出现了三个小方块 

 

下面我就使用单例模式,让它只建立一个div 

var createDiv = (function(){
    var div;
    return function(){
        if(!div){
            div = document.createElement('div');
            div.style.width = '100px';
            div.style.height = '100px';
            div.style.background = 'red';
            div.style.marginBottom = '10px';
            document.body.appendChild(div);
        }
    }
})();
createDiv();
createDiv();
createDiv();

 再来看看页面,只有一个小方块 

 

div声明在当即执行函数中做为私有变量 ,没有执行函数前, div值为undefined ,第一次执行函数时,判断div,若是没有,建立了一个DOM节点而且插入到了文档; 随后再执行函数时,div变量已经缓存了刚刚建立的DOM节点,再也不建立 ,不管执行几回,小方块只会建立一次 ,这就是单例模式,并且是一个惰性单例。

惰性单例就是在须要的时候才建立对象实例,而非在页面加载时就建立 ,这样作的好处你们都知道。

 

虽然咱们完成了惰性单例,可是咱们一样发现了问题

  • 违反了单一职责原则,建立对象和管理单例放在了一个函数中createDiv
  • 若是咱们还想建立一个其余的惟一对象,那就只能copy了

综上,咱们须要把不变的部分隔离出来,把可变的封装起来,这给予了咱们扩展程序的能力,符合“开放-封闭原则”;

下面咱们就抽出管理单例的逻辑 ,不管怎样抽取,万变不离其中,用一个变量来标志是否建立过对象

var getSingle = function(fn){
    var result;
    return function(){
        return result || (result = fn.apply(this, arguments));
    }
};
var createDiv = function(){
    var div = document.createElement('div');
    div.style.width = '100px';
    div.style.height = '100px';
    div.style.background = 'red';
    div.style.marginBottom = '10px';
    document.body.appendChild(div);
    return div;
};
var createSingleDiv = getSingle(createDiv);
createSingleDiv();
createSingleDiv();
createSingleDiv();

建立的DOM节点保存在了result中 ,result变量由于自身在闭包中,不会被销毁,若是result已经被赋值了,那么它将返回这个值 ;

单例模式很简单,并且也十分实用,他不只仅用于建立对象,还有不少其余用途 ,好比说只绑定一次事件啦之类的

相关文章
相关标签/搜索