JavaScript设计模式--单例模式

单例模式

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

    单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏 览器中的 window 对象等。在 JavaScript 开发中,单例模式的用途同样非常广泛。试想一下,当我 们单击登录按钮的时候,页面中会出现一个登录浮窗,而这个登录浮窗是唯一的,无论单击多少次登录按钮,这个浮窗都只会被创建一次,那么这个登录浮窗就适合用单例模式来创建。

  • 实现一个单例模式

    单例模式的实现并不复杂,无非是用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象。

  • 代码:

var Singleton = function( name ){ 
    this.name = name; this.instance = null;
};
Singleton.prototype.getName = function(){ 
    alert ( this.name );
};
Singleton.getInstance = function( name ){ 
    if ( !this.instance ){
    this.instance = new Singleton( name ); }
    return this.instance; 
};
var a = Singleton.getInstance( 'sven1' ); 
var b = Singleton.getInstance( 'sven2' );
alert ( a === b ); // true

JavaScript中的单例模式

基于类的单例模式在JavaScript中并不适用。全局变量不是单例模式,但在JavaScript中经常把全局变量当成单例模式来使用,但全局变量存在很多问题,很容易造成命名空间污染,以生命的变量很容易被别人覆盖。以下几种方式可以相对降低全局变量带来的命名污染:

  • 使用命名空间:
var MyApp = {};
MyApp.namespace = function( name ){ 
   var parts = name.split( '.' ); 
   var current = MyApp;
   for ( var i in parts ){
       if ( !current[ parts[ i ] ] ){ 
           current[ parts[ i ] ] = {};
       }
       current = current[ parts[ i ] ];
   }
}
MyApp.namespace( 'event' ); 
MyApp.namespace( 'dom.style' );
console.log(MyApp)
//{namespace: ƒ, event: {}, dom: {style:{}}

  • 使用闭包封装私有变量:

    把一些变量封装在闭包的内部,只暴露一些接口跟外界通信,例如:

    var user = (function(){ 
        var __name = 'sven',
            __age = 29;
            
        return {
            getUserInfo: function(){
                return __name + '-' + __age; 
            }
        } 
    })();
    

    其中,用下划线来约定私有变量__name和__age,外界无法访问,避免来对全局的命令污染。

栗子

  • 使用场景:webQQ页面,点击登录才弹出来登录框,而且不需要重复的创建,只创建一次,需要的时候拿出来就可以了,也就是单例模式。代码如下:
var createLoginLayer = (function(){ 
    var div;
    return function(){ 
        if ( !div ){
            div = document.createElement( 'div' );
            div.innerHTML = '我是登录浮窗';
            div.style.display = 'none';
            document.body.appendChild( div );
        }
        return div; 
    }
})();

document.getElementById( 'loginBtn' ).onclick = function(){ 
    var loginLayer = createLoginLayer();
    loginLayer.style.display = 'block';
};

通用的惰性单例

上述代码虽然完成了一个可用的惰性单例,但他还存在两个问题:

  • 这段代码仍然是违反单一职责原则的,创建对象和管理单例的逻辑都放在 createLoginLayer 对象内部
  • 如果我们下次需要创建页面中唯一的 iframe,或者 script 标签,用来跨域请求数据,就 必须得如法炮制,把 createLoginLayer 函数几乎照抄一遍

于是我们把不变的部分提取出来,将创建单例的逻辑封装在getSingle函数内部:

var getSingle = function( fn ){
    var result;
    return function(){
        return result || ( result = fn .apply(this, arguments ) );
    } 
};
//接下来无论要创建login登录框还是iframe,只要把创建函数写好传给getSingle函数就行了
var createLoginLayer = function(){
    var div = document.createElement( 'div' );
    div.innerHTML = '我是登录浮窗';
    div.style.display = 'none'; 2 document.body.appendChild( div );
    return div;
};

var createSingleLoginLayer = getSingle( createLoginLayer );

document.getElementById( 'loginBtn' ).onclick = function(){ 
    var loginLayer = createSingleLoginLayer();
    loginLayer.style.display = 'block';
};//创建iframe也一样
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值