javascript设计模式(1)——单例模式

2026-04-28 14:59:28 206
分类:设计模式

1. 单例模式的特点和定义

  • 一个类只有一个实例

  • 对外提供唯一的访问接口

2. 单例模式的实现

2.1 对象字面量

var mySingleton = {
    attr1:1,
    attr2:2,
    method:function (){
        console.log("method");    
    }
}

以上创建一个对象,放在全局中,就可以在任何地方访问,要访问对象中的属性和方法,必须通过mySingleton这个对象,也就是说提供了唯一一个访问接口。

缺陷:

这样的方式耦合度极高,例如:要给这个对象添加属性:

mySingleton.width = 1000;  //添加一个属性

//添加一个方法会覆盖原有的方法
mySingleton.method = function(){};

如果在多人协作中,这样添加属性的方式经常出现被覆盖的危险,可以采用命名空间的方式解决。

//A同学
mySingleton.a = {};
mySingleton.a.method = function(){}

都在自己的命名空间中,覆盖的几率会很小。

2.2 使用闭包私有化

扩展mySingleton对象,添加私有的属性和方法,使用闭包的形式在其内部封装变量和函数声明,只暴露公共成员和方法。

var mySingleton = (function (){
    //私有变量
    var privateVal = '我是私有变量';
    //私有函数
    function privateFunc(){
        console.log('我是私有函数');    
    }
    // 自执行时就返回了一个对象,造成内存浪费
    return {
            attr1:1,
            attr2:2,
            method:function (){
                console.log("method");    
                privateFunc();
            }
        }    
})();

mySingleton.method();

缺陷:

脚本一加载就被创建,造成资源浪费。

2.3 惰性单例

无论使用对象字面量或者闭包私有化的方式创建单例,都是在脚本一加载就被创建。有时候页面可能不会用到这个单例对象,这样就会造成资源浪费。对于这种情况,最佳处理方式是使用惰性单例,也就是在需要这个单例对象时再初始化。

惰性单例指的是在需要的时候才创建对象的实例。惰性单例是单例模式的重点。

var createLoginLayer=(function(){
    var div; // 当自执行时div为undefined
    return function(){
        if(!div){
            div=document.createElement('div');
        }
        return div; // 当调用函数时返回div对象
    }
})();

2.4. 使用构造函数

可以使用构造函数的方式,创造单例对象,这是一个透明的单例模式:

function mySingleton(){
    //如果缓存了实例,则直接返回
    if (mySingleton.instance) {
        return mySingleton.instance;
    }

    //当第一次实例化时,先缓存实例
    mySingleton.instance = this;
}

mySingleton.prototype.otherFunc = function (){
    console.log("原型上其他方法");    
}

var p1 = new mySingleton();
var p2 = new mySingleton();

console.log( p1 === p2 );  //true

当第一次使用new调用函数创建实例时,通过函数的静态属性mySingleton.instance把实例缓存起来,在第二次用new调用函数,判断实例已经缓存过了,直接返回,那么第一次得到的实例p1和第二次得到的实例p2是同一个对象。

缺陷:

但是这样做有一个问题,暴露了可以访问缓存实例的属性mySingleton.instance,这个属性的值可以被改变,如果改变后p1不再等于p2。