转载于原文地址: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已经被赋值了,那么它将返回这个值 ;

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

JS设计模式——单例模式剖析的更多相关文章

  1. js设计模式-单例模式

      JavaScript中的单例模式是最常用的.最基本的设计模式,它提供了一种命名空间,减少全局变量泛滥的代码管理机制: 1.最常见的单例模式: [javascript] view plain cop ...

  2. [js]js设计模式-单例模式

    单例模式 不同模块之间需要同时开发, // 单例模式: 把描述同一个事物的属性和方法放在同一个内存空间下. // 优点: 分组,防止冲突 // p1 p2也叫做命名空间(模块开发) var p1 = ...

  3. js 设计模式——单例模式

    单例模式 保证一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池.全局缓存.浏览器中的 window 对象等. JavaScript ...

  4. [转]JS设计模式-单例模式(二)

    单例模式是指保证一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式是一种常用的模式,有一些对象往往只需要一个,比如线程池.全局缓存.浏览器中的window对象等.在javaScript开发中 ...

  5. ES6教程-字符串,函数的参数,了解函数的arguments对象,js面向对象,设计模式-单例模式,解构赋值

    前言 主要讲解了ES6对字符串的拓展,包括includes,startsWith和endsWith,另外增加了字符串模板. Start includes()是否包含 startsWith()以什么开头 ...

  6. JS设计模式(一)

    刚入职时,看过一段时间的设计模式,似懂非懂.不知不觉过去七个月了,对JS的理解更深刻了,数据结构与算法的基础也基本上算是过了一遍了,接下来要把设计模式搞定,然后不再深层次研究JS了,而是学习前端自动化 ...

  7. JavaScript设计模式-单例模式、模块模式(转载 学习中。。。。)

    (转载地址:http://technicolor.iteye.com/blog/1409656) 之前在<JavaScript小特性-面向对象>里面介绍过JavaScript面向对象的特性 ...

  8. js设计模式总结1

    js设计模式有很多种,知道不代表会用,更不代表理解,为了更好的理解每个设计模式,对每个设计模式进行总结,以后只要看到总结,就能知道该设计模式的作用,以及模式存在的优缺点,使用范围. 本文主要参考张容铭 ...

  9. JS实现单例模式的多种方案

    JS实现单例模式的多种方案 今天在复习设计模式中的-创建型模式,发现JS实现单例模式的方案有很多种,稍加总结了一下,列出了如下的6种方式与大家分享 大体上将内容分为了ES5(Function)与ES6 ...

随机推荐

  1. 在C#中,Json的序列化和反序列化的几种方式总结 转载

    转载自  https://www.cnblogs.com/caofangsheng/p/5687994.html    谢谢 在这篇文章中,我们将会学到如何使用C#,来序列化对象成为Json格式的数据 ...

  2. jmeter接口测试-文件下载

    http://imgsrc.baidu.com/forum/pic/item/a89b033b5bb5c9ea901d1997dd39b6003bf3b3dc.jpg    网上找了一张高圆圆的图片 ...

  3. angular.copy()

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. PHP06

    PHP06 1. 2.可视化工具navicat: 1)查询 : select 字段名1,字段名2- from 表名; 对于可能与关键词重名的名称,建议使用反引号`括起来 可用*通配符代替字段名 sel ...

  5. Linux配置防火墙,开启80端口、3306端口

    Linux配置防火墙,开启80端口.3306端口   起因是因为想使用Navicat连接一下数据库,发现连接不上 通过查阅许多资料和多次测试发现是因为防火墙没有配置3306端口 话不多说,开整,同理, ...

  6. 部署Bookinfo示例程序详细过程和步骤(基于Kubernetes集群+Istio v1.0)

    部署Bookinfo示例程序详细过程和步骤(基于Kubernetes集群+Istio v1.0) 部署Bookinfo示例程序   在下载的Istio安装包的samples目录中包含了示例应用程序. ...

  7. OUTLOOK - Unable to Delete Meetings

    Error Information: Resolved: Check Meeting room permission.Get-MailboxFolderPermission MeetingRoom_1 ...

  8. 【Java】maven多项目资源共享

    方案一: <resources> <resource> <!-- <directory>${project.parent.relativePath}/../. ...

  9. [Vuex] Lazy Load a Vuex Module at Runtime using TypeScript

    Sometimes we need to create modules at runtime, for example depending on a condition. We could even ...

  10. 配置带用户权限的docker registry v2

    v1版本的docker registry用nginx配置,v2版本的用nginx有些问题,客户端总是会请求到v1/下面去, 以下从 http://blog.csdn.net/felix_yujing/ ...