aermin/blog

js设计模式-单例模式

Opened this issue · 0 comments

单例模式:

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

例子:单击登录按钮的时候,页面中会出现一个登录浮窗,而这个登录浮窗是唯一的,无论单击多少 次登录按钮,这个浮窗都只会被创建一次,那么这个登录浮窗就适合用单例模式来创建。

实现思路:用一个变量来标志当前是否已经为某个类创建 过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象。

image

以上是接近传统面向对象语言中的实现,单例对象从 “类”中创建而来。

JavaScript 其实是一门无类(class-free)语言,也正因为如此,生搬单例模式的概念并无 意义。在 JavaScript 中创建对象的方法非常简单,既然我们只需要一个“唯一”的对象。

js版本定义:保证一个全局对象仅有一个实例,提供给全局访问。

全局变量不是单例模式,但在 JavaScript 开发中,我们经常会把全局变量当成单例来使用。 例如:

var a = {};

当用这种方式创建对象 a 时,对象 a 确实是独一无二的。如果 a 变量被声明在全局作用域下, 则我们可以在代码中的任何位置使用这个变量,全局变量提供给全局访问是理所当然的。这样就 满足了单例模式的两个条件。

但是全局变量存在很多问题,它很容易造成命名空间污染。在大中型项目中,如果不加以限 制和管理,程序中可能存在很多这样的变量。JavaScript 中的变量也很容易被不小心覆盖,相信 每个 JavaScript 程序员都曾经历过变量冲突的痛苦,就像上面的对象 var a = {};,随时有可能被 别人覆盖。

以下几种方式可以相对降低全局变量带来的命名污染:

1.使用命名空间

适当地使用命名空间,并不会杜绝全局变量,但可以减少全局变量的数量。
最简单的方法依然是用对象字面量的方式:

var namespace1 = { 
    a: function(){ 
        alert (1); 
    }, 
    b: function(){ 
        alert (2); 
    } 
};

2.使用闭包封装私有变量
这种方法把一些变量封装在闭包的内部,只暴露一些接口跟外界通信:

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

我们用下划线来约定私有变量__name 和__age,它们被封装在闭包产生的作用域中,外部是 访问不到这两个变量的,这就避免了对全局的命令污染。

  1. 单例模式的实际运用 (惰性单例,抽离单例管理)

code

//抽象出创建单例的方法
var getSingle = function( fn ){ 
    var result; 
    return function(){ 
        return result || ( result = fn .apply(this, arguments ) ); 
    } 
};
//创建惰性单例函数
var createLoginLayer = function(){ 
    var div = document.createElement( 'div' );
    div.innerHTML = '我是登录浮窗';
    div.style.display = 'none'; 
    document.body.appendChild( div ); 
    return div; 
};
var createSingleLoginLayer = getSingle( createLoginLayer );
//使用惰性单例函数
document.getElementById( 'loginBtn' ).onclick = function(){ 
    var loginLayer = createSingleLoginLayer(); 
    loginLayer.style.display = 'block'; 
};

内容整理自 《JavaScript设计模式与开发实践》