javascript单例模式的理解
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";
};
编写通用的惰性单例
如上代码虽然完成了惰性单例,但是有些问题;
- 违反了单一职责原则;比如创建对象和管理单例的逻辑都放在CreateDiv对象内部;
- 没有把代码抽象出来,比如上面的是创建一个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呢,这就是单例模式只创建一个实例的地方;
javascript单例模式的理解的更多相关文章
- JAVA Static方法与单例模式的理解
近期用sonar測评代码质量的时候,发现一个问题,project中一些util类,曾经写的static方法都提示最好用单例的方式进行改正. 为此,我细致想了想,发现还是非常有道理的.这里谈谈我个人对s ...
- JavaScript面向对象的理解
JavaScript面向对象的理解 笔记链接: http://pan.baidu.com/s/1c0hivuS 1:JavaScript 中分两种对象,函数对象和普通对象new Function() ...
- 浅析Javascript单例模式
定义 保证一个类仅有一个实例,并提供一个访问它的全局访问点 .就想我们在开发中有些对象只需要一个,例如window对象. 1. 实现单例模式 var Singleton = function( nam ...
- [转] JavaScript 单例模式
定义 确保一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式使用的场景 比如线程池.全局缓存等.我们所熟知的浏览器的window对象就是一个单例,在JavaScript开发中,对于这种只需要 ...
- javascript javascript面向对象的理解及简单的示例
javascript面向对象的理解及简单的示例 零.本节重点: 1.封装: 2.继承: 壹.下面理解: 一. javascript面向对象概念: 为了说明 JavaScript 是一门彻底的面向对象的 ...
- JAVA设计模式 1 设计模式介绍、单例模式的理解与使用
数据结构我们已经学了一部分了.是该了解了解设计模式了.习惯了CRUD的你,也该了解了解这一门神器.我为啥要说是神器呢? 因为在大厂的面试环节.以及很多的比如 Springboot Mybatis 等开 ...
- javaScript深入浅出之理解闭包
javaScript深入浅出之理解闭包 引言 闭包是个老生长谈的话题了,对于闭包网上也有很多不同的看法 <你不知道的javaScript>对于闭包是这么定义的:函数创建和函数执行不在同一个 ...
- 深入理解 JavaScript 单例模式 (Singleton Pattern)
概念 单例模式,也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对象的类必须保证只有一个实例存在. 核心:确保只有一个实例,并提供全局访问. 实现思路 一个类能返回对象一个引用(永远是同 ...
- Javascript单例模式概念与实例
前言 和其他编程语言一样,Javascript同样拥有着很多种设计模式,比如单例模式.代理模式.观察者模式等,熟练运用Javascript的设计模式可以使我们的代码逻辑更加清晰,并且更加易于维护和重构 ...
随机推荐
- LINUX下C语言编程基础
实验二 Linux下C语言编程基础 一.实验目的 1. 熟悉Linux系统下的开发环境 2. 熟悉vi的基本操作 3. 熟悉gcc编译器的基本原理 4. 熟练使用gcc编译器的常用选项 5 .熟练使用 ...
- 20145222黄亚奇《Java程序设计》第7周学习总结
教材学习内容总结 第十三章 时间与日期 即使标注为GMT(格林威治时间),实际上谈到的的是UTC(Unix时间)时间. 秒的单位定义时基于TAI.也就是铯原子辐射的振动次数. Unix时间是1970年 ...
- 1.SQLAlchemy文档-简介(中文版)
Python的SQL工具包和对象关系映射器 SQLAlchemy的是Python的SQL工具包和对象关系映射器,让应用程序开发人员可以使用上SQL的强大功能和灵活性. 它提供了一套完整 ...
- 翻译-微服务API Gateway
原文地址:http://microservices.io/patterns/apigateway.html,以下是使用google翻译对原文的翻译. 让我们想象一下你正在建立一个使用微服务模式的网上商 ...
- Object C学习笔记17-动态判断和选择器
当时学习Object C的时被人鄙视了一顿,说使用.NET的思想来学Object C就是狗屎:不过也挺感谢这位仁兄的,这让我学习的时候更加的谨慎.今天的学习笔记主要记录Object C中的动态类型相关 ...
- Pivot的SelectionChanged事件绑定到VM的Command
我要实现的是页面加载时,只获取SelectedIndex=0的数据,然后根据Pivot的SelectionChanged动态获取其他项的数据,我用的是MVVM的Command的方式,不想用后台注册事件 ...
- 记录nginx 搭建集群环境踏过的坑
因为生产环境做了负载均衡,为了尽可能跟线上环境一致,所以想在本地也搭集群,这样测试更靠谱.首先就想到nginx 这货,搭个简单的web 服务器实在太简单了. nginx 这玩意11年简单玩过,那是版本 ...
- JQuery学习(1)
JQuery学前准备 JQuery的各种包: 1.jquery-ui(包含小工具及组件) 2.jquery-1.7.1.intellisense.js(智能提示包) 3.jquery-1.7.1.js ...
- codevs 1835 魔法猪学院 A*寻k短路做了一个月卡死在spfa那了/(ㄒoㄒ)/~~
SPFA时点出队后一定要把在队内的标记置为false!SPFA时点出队后一定要把在队内的标记置为false!SPFA时点出队后一定要把在队内的标记置为false! 我因为这个卡了一个月大家信吗?测得时 ...
- (BZOJ4538)HNOI2016 网络
HNOI2016 Day1 T2 网络 Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做一条树边.两个服务器进行数据的交互时,数 ...