javascript单例模式的理解

阅读目录

  • 理解单例模式
  • 使用代理实现单例模式
  • 理解惰性单例
  • 编写通用的惰性单例
  • 单例模式使用场景

回到顶部

理解单例模式

单例模式的含义是: 保证一个类只有一个实例,并提供一个访问它的全局访问点。实现的方法是:使用一个变量来标志当前是否已经为某个类创建过对象,如果创建了,则在下一次获取该类的实例时,直接返回之前创建的对象,否则就创建一个对象。这就确保了一个类只有一个实例对象。

比如如下代码是一个简单的单例模式代码实例:

var Singleton = function(name){
    this.name = name;
    // 使用instance 该标志来判断是否创建了一个实例
    this.instance = null;
};
Singleton.prototype.getName = function(){
    console.log(this.name);
};
Singleton.getInstance = function(name) {
    if(!this.instance) {
        this.instance = new Singleton(name);
    }
    return this.instance;
}

现在我们可以来使用下,初始化下,如下代码:

var a = Singleton.getInstance("aa");
var b = Singleton.getInstance("bbb");
console.log(a);
console.log(b);

打印如下:

继续如下测试:

console.log(a === b);  // true

a.getName();  // aa

b.getName();  // aa

a.test = "test";

console.log(b.test); // test

如上代码测试,可以看到,先是实例化一次,传aa给name参数,保存到a变量中,第二次再次调用getIstance方法,由于实例已经存在,所以使用之前第一次创建过的对象,因此 a ===b 为true,a.getName()和b.getName()值打印都为aa;

我们还可以像如下方式来编写代码:

var Singleton = function(name){
    this.name = name;
};
Singleton.prototype.getName = function(){
    console.log(this.name);
};
Singleton.getInstance = (function(){
    var instance = null;
    return function(name){
        if(!instance) {
            instance = new Singleton(name);
        }
        return instance;
    }
})();

回到顶部

使用代理实现单例模式

比如我现在想在页面上创建一个div元素,如下使用代理实现单例模式的代码:

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("aa");
var b = new ProxySingletonCreateDiv("bbb");
console.log(a === b); // true

如上代码:我们把负责管理单例的逻辑移到了ProxySingletonCreateDiv 函数中,CreateDiv函数就是一个普通的函数,就是只是负责创建div的方法,那么具体的管理单例的逻辑交给ProxySingletonCreateDiv函数;

回到顶部

理解惰性单例

惰性单例的含义是:在需要的时候才创建对象实例,而前面我们讲的是页面加载完的时候就创建实例;比如我们在页面上一个弹出窗口的div,还有许多其他的显示元素,如果有些用户不点击那个弹窗的话,那么在页面初始化的时候多创建了一些dom节点,如果我们使用惰性单例的话,我们就可以在用户需要的时候才去创建dom节点;

我们首先来看看在页面加载完成的时候去创建div弹窗。这个弹窗一开始是隐藏的,当用户点击某个按钮的时候,这个弹窗才显示;代码如下:

<button id="btn">请点击我</button>

var CreateDiv = (function(){
    var div = document.createElement(‘div‘);
    div.innerHTML = "我是弹窗测试";
    div.style.display = "none";
    document.body.appendChild(div);
    return div;
})();
document.getElementById("btn").onclick = function(){
    CreateDiv.style.display = "block";
};
惰性代码如下所示:
var CreateDiv = function(){
    var div = document.createElement(‘div‘);
    div.innerHTML = "我是弹窗测试";
    div.style.display = "none";
    document.body.appendChild(div);
    return div;
};
document.getElementById("btn").onclick = function(){
    var createDiv = CreateDiv();
    createDiv.style.display = "block";
};

如上代码,我们点击按钮的时候,才去创建div元素,但是每次点击的时候,我们都得创建元素,这样也不合理的。但是如上代码,我们可以使用一个变量来判断是否已经创建过div弹窗;如下所示:

var CreateDiv = (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("btn").onclick = function(){
    var createDiv = CreateDiv();
    createDiv.style.display = "block";
};

回到顶部

编写通用的惰性单例

如上代码虽然完成了惰性单例,但是有些问题;

  1. 违反了单一职责原则;比如创建对象和管理单例的逻辑都放在CreateDiv对象内部;
  2. 没有把代码抽象出来,比如上面的是创建一个div元素,但是以后我想创建一个script元素或者一个iframe元素的话,那么我们还需要复制上面的代码重写下;

比如如果我现在按照上面创建div的方法,现在我们需要再创建一个iframe元素的话,代码需要改成如下:

var createIframe = (function(){
    var iframe;
    return function(){
        if(!iframe) {
            iframe = document.createElement(‘iframe‘);
            iframe.style.display = ‘none‘;
            document.body.appendChild(iframe);
        }
        return iframe;
    }
})();

我们现在肯定在考虑如何把上面的代码公用出来,这样就可以实现抽象的代码,管理单例的逻辑代码其实可以抽象出来,这个逻辑是一样的,使用一个变量来标志是否创建过对象,如果是,在下次直接返回这个已经创建好的对象;

我们可以把这些逻辑封装在getSingle函数内部,创建对象的方法fn被当成参数动态传入getSingle函数;如下代码:

var getSingle = function(fn){
    var result;
    return function(){
        return result || (fn.apply(this,arguments));
    };
};

下面我们是使用getSingle创建一个div的方法如下:

var CreateDiv = function(){
    var div = document.createElement(‘div‘);
    div.innerHTML = "我是弹窗测试";
    div.style.display = "none";
    document.body.appendChild(div);
    return div;
};
// 创建单例
var createSingleDiv = getSingle(CreateDiv); 

document.getElementById("btn").onclick = function(){
    // 调用单例方法
    var createDiv = createSingleDiv();
    createDiv.style.display = "block";
};

比如现在我们需要创建一个iframe,那么代码如下:

var createSingleIframe = getSingle(function(){
    var iframe = document.createElement(‘iframe‘);
    document.body.appendChild(iframe);
    return iframe;
});
document.getElementById("btn").onclick = function(){
    // 调用单例方法
    var createSingleIframe = createSingleIframe();
    createSingleIframe.src = "http://cnblogs.com";
};

回到顶部

单例模式使用场景

有一些对象我们只需要一个的情况下,比如弹窗这样的,全局缓存,游览器window对象等。

单例模式只会创建一个实例,且仅有一个实例,比如我们一刚开始讲到的,

var a = Singleton.getInstance("aa");

var b = Singleton.getInstance("bbb");

console.log(a === b);  // true

a.getName();  // aa

b.getName();  // aa

我们明明第一次传的是aa,第二次传的参数是bbb,为什么都调用getName()方法后都打印出aa呢,这就是单例模式只创建一个实例的地方;

时间: 2024-10-25 18:03:21

javascript单例模式的理解的相关文章

JAVA Static方法与单例模式的理解

近期用sonar測评代码质量的时候,发现一个问题,project中一些util类,曾经写的static方法都提示最好用单例的方式进行改正. 为此,我细致想了想,发现还是非常有道理的.这里谈谈我个人对static方法与单例模式的理解. 所谓单例模式,我不做过多解释,推荐java设计模式之禅这本书,好好理解一下. 这里我谈谈两种写法: 曾经一些公共的类,我不假思索,习惯依照例如以下写法去写: public class DateUtil { public final static String DAT

JavaScript大杂烩6 - 理解JavaScript中的this

在JavaScript开发中,this是很常用的一个关键字,但同时也是一个很容易引入bug的一个关键字,在这里我们就专门总结一下页面中可能出现的this关键字(包括几种在其他页面文件中出现的this). JavaScript中的this关键字通常只使用在函数中,它指向当前函数的调用者,这是this关键字的本质,所有的使用方式都是围绕这个展开的,让我们来看一下在各种性质的函数中this的用法.1. 在对象的函数中使用this var person = { name: 'Frank', say: f

【JavaScript】深入理解JavaScript之强大的原型和原型链

由于JavaScript是唯一一个被广泛使用的基于原型继承的语言,所以理解两种继承模式的差异是需要一定时间的,今天我们就来了解一下原型和原型链. AD: hasOwnProperty函数: hasOwnProperty是Object.prototype的一个方法,它可是个好东西,他能判断一个对象是否包含自定义属性而不是原型链上的属性,因为hasOwnProperty 是 JavaScript 中唯一一个处理属性但是不查找原型链的函数. // 修改Object.prototype Object.p

JavaScript大杂烩12 - 理解Ajax

AJAX缘由 再次谈起这个话题,我深深的记得就在前几年,AJAX被炒的如火如荼,就好像不懂AJAX,就不会Web开发一样.要理解AJAX为什么会出现,就要先了解Web开发面临的问题. 我们先来回忆一下Web页面的申请过程,这个咱们在第一篇中就介绍过了:Web页面开发就是在无连接和无状态的HTTP协议上管理页面的状态.每次申请页面的时候,服务器都会返回完整的HTML文本(当然还有其他的文本文件),浏览器就负责解析这个文本并在浏览器中显示. 在这个过程中,不管当前页面的内容是不是都变化了,服务器都会

JavaScript大杂烩7 - 理解内置集合

JavaScript内置了很多对象,简单的类型如String,Number,Boolean (相应的"值类型"拥有相同的方法),复杂一点的如Function,Object,Array,它们支撑起来JavaScript编程的基石.由于Number与Boolean很简单,这里就不多说了,下面着重介绍其他的内置对象. 万物之源 - Object对象 JavaScript是单根的,唯一的根就是Object对象,这个对象提供了几个还是不错的方法,值得了解一下. 1. hasOwnProperty

JavaScript大杂烩8 - 理解文本解析的"黄金搭档"

文本解析"黄金搭档" - String与RegExp对象 文本解析是任何语言中最常用的功能,JavaScript中也是一样,而正则表达式作为最常用的方式,JavaScript也同样是支持的,下面就来看看字符串对象与正则表达式对象的配合. 字符串的恒定性 在正式开始讨论字符串对象的成员之前,我们需要了解一点,那就是:与C#一样,JavaScript 的字符串是不可变的(immutable),String对象定义的方法都不会改变字符串的内容.像toUpperCase这样的方法,返回的是全新

[JavaScript原型继承理解一]

转:http://www.cnblogs.com/harolei/p/3740354.html 对于JavaScript的继承和原型链,虽然之前自己看了书也听了session,但还是一直觉得云里雾里,不禁感叹JavaScript真是一门神奇的语言.这次经过Sponsor的一对一辅导和自己回来后反复思考,总算觉得把其中的精妙领悟一二了. 1. JavaScript创建对象 在面向对象语言中,通常通过定义类然后再进行实例化来创建多个具有相同属性和方法的对象.但是在JavaScript中并没有类的概念

javascript单例模式(懒汉 饿汉)

第一种:懒汉模式 var Singleton=(function(){ var instantiated; //比较懒,在类加载时,不创建实例,因此类加载速度快,但运行时获取对象的速度慢 function init(){ /*这里定义单例代码*/ return{ publicMethod:function(){ console.log('helloworld'); }, publicProperty:3 }; } return{ getInstance:function(){ if(!insta

JavaScript大杂烩9 - 理解BOM

毫无疑问,我们学习JavaScript是为了完成特定的功能.在最初的JavaScript类型系统中,我们已经分析过JavaScript在页面开发中充当着添加逻辑的角色,而且我们知道JavaScript不仅仅包含基本的语法规范.下面我们就重点看一下JavaScript在页面中干的那些事.总的来说,JavaScript在页面端就干两件事:操作DOM与操作BOM (当然了向Server获取数据也是它的工作,不过获取到数据后还是回来干这两件事,大家对JavaScript最直接的印象应该就是各种光怪陆离的