转载于原文地址:https://blog.csdn.net/q1056843325/article/details/52933426

举一个通俗的例子,在页面中点击登录按钮,弹出了一个登录浮窗,这个登录浮窗是唯一的,无论我们单击多少次,浮窗只会创建一次。

其实我们可能无意中都会使用过单例模式,我们的做法往往都是使用一个变量来标志当前是否已经为某个类创建了对象, 如果true,那么下一次再想获得这个类的实例时,直接返回之前创建过的对象。

单例模式的核心是确保只有一个实例,并提供全局访问。

其实在JavaScript中,单例模式并没有这么复杂

var a = {};

我们这样创建了对象a,它确实独一无二 
而且满足了单例模式的两个条件

  • 一个实例
  • 全局访问

但是全局变量很容易造成命名空间污染 ,如果项目很大的话,不小心覆盖了变量那就是致命的。

所以,在详细讲解这个单例模式之前,我们先来讨论这样一个问题,怎样降低全局污染? (全局污染也就是变量大量存在于全局作用域污染了全局空间 )

降低全局污染有两种办法:

1、使用命名空间

var namespace_payen = {
a: function(){
//...
}
b: function(){
//...
}
}

适当使用命名空间,并不会杜绝全局变量,但是可以减少全局变量的数量

2、使用闭包封装私有变量

var payen = (function(){
var _name = 'payson.Tsung',
_age = ;
return {
getInfo: function(){
return _name + ' ' + _age;
}
}
})();

变量被封装在了闭包内,只暴露一些接口用于外部通信,从而避免了对全局的命令污染

下面我来谈谈这个单例模式

先来个简单的例子

下面我声明了一个函数,每次调用都创建一个小方块

function createDiv(){
var div = document.createElement('div');
div.style.width = '100px';
div.style.height = '100px';
div.style.background = 'red';
div.style.marginBottom = '10px';
document.body.appendChild(div);
}
createDiv();
createDiv();
createDiv();

调用了三次,页面出现了三个小方块

下面我就使用单例模式,让它只创建一个div

var createDiv = (function(){
var div;
return function(){
if(!div){
div = document.createElement('div');
div.style.width = '100px';
div.style.height = '100px';
div.style.background = 'red';
div.style.marginBottom = '10px';
document.body.appendChild(div);
}
}
})();
createDiv();
createDiv();
createDiv();

再来看看页面,只有一个小方块

div声明在立即执行函数中作为私有变量 ,没有执行函数前, div值为undefined ,第一次执行函数时,判断div,如果没有,创建了一个DOM节点并且插入到了文档; 随后再执行函数时,div变量已经缓存了刚刚创建的DOM节点,不再创建 ,无论执行几次,小方块只会创建一次 ,这就是单例模式,而且是一个惰性单例。

惰性单例就是在需要的时候才创建对象实例,而非在页面加载时就创建 ,这样做的好处大家都知道。

虽然我们完成了惰性单例,但是我们同样发现了问题

  • 违反了单一职责原则,创建对象和管理单例放在了一个函数中createDiv
  • 如果我们还想创建一个其他的唯一对象,那就只能copy了

综上,我们需要把不变的部分隔离出来,把可变的封装起来,这给予了我们扩展程序的能力,符合“开放-封闭原则”;

下面我们就抽出管理单例的逻辑 ,无论怎样抽取,万变不离其中,用一个变量来标志是否创建过对象

var getSingle = function(fn){
var result;
return function(){
return result || (result = fn.apply(this, arguments));
}
};
var createDiv = function(){
var div = document.createElement('div');
div.style.width = '100px';
div.style.height = '100px';
div.style.background = 'red';
div.style.marginBottom = '10px';
document.body.appendChild(div);
return div;
};
var createSingleDiv = getSingle(createDiv);
createSingleDiv();
createSingleDiv();
createSingleDiv();

创建的DOM节点保存在了result中 ,result变量因为自身在闭包中,不会被销毁,如果result已经被赋值了,那么它将返回这个值 ;

单例模式很简单,而且也十分实用,他不仅仅用于创建对象,还有很多其他用途 ,比如说只绑定一次事件啦之类的

最新文章

  1. ACM/ICPC 之 混合图的欧拉回路判定-网络流(POJ1637)
  2. Java中为什么有abstract interface 修饰类?
  3. iOS Assertion failure in -[UITableView _configureCellForDisplay:forIndexPath:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.30.14/UITableView.m:7962
  4. python(九)re模块
  5. saltstack实战2--远程执行之返回(returner)
  6. Apache Avro 与 Thrift 比较
  7. MyBatis学习笔记(2)——缓存
  8. libvirt-adabddad
  9. c#委托事件入门--第一讲:委托入门
  10. java异常,异常处理,异常类 关键字:throws 和 throw 自定义的异常类
  11. ajax的一些相关
  12. 洛谷CF1071E Rain Protection(计算几何,闵可夫斯基和,凸包,二分答案)
  13. python3 文件和流
  14. GWAS研究可利用的数据库(持续更新)
  15. JAVA核心技术I---JAVA基础知识(static关键字)
  16. Hibernate_day01
  17. Maven 入门篇 ( 上 )
  18. python 使用selenium和requests爬取页面数据
  19. Mycat常见错误
  20. redis 基本概览

热门文章

  1. day4函数文件操作
  2. javascript中的常用表单事件用法
  3. [Nuget]使用Nuget管理工具包
  4. kettle 6.1 通过JS脚本与SwitchCase结合实现目标步骤选择
  5. Python 汉字转拼音
  6. 遇到一个git branch很奇怪的问题
  7. SSE图像算法优化系列二十五:二值图像的Euclidean distance map(EDM)特征图计算及其优化。
  8. KVM之CPU虚拟化
  9. edis更新的正确方法
  10. 自建k8s集群日志采集到阿里云日志服务