摘要:文章系列设计模式单例模式设计模式策略模式设计模式代理模式概念单例模式的定义是保证一个类仅有一个实例,并提供一个访问它的全局访问点。在开发中,单例模式的用途同样非常广泛。
前言
本系列文章主要根据《JavaScript设计模式与开发实践》整理而来,其中会加入了一些自己的思考。希望对大家有所帮助。
文章系列js设计模式--单例模式
js设计模式--策略模式
js设计模式--代理模式
概念单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
UML类图 场景单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏 览器中的 window 对象等。
在 JavaScript 开发中,单例模式的用途同样非常广泛。试想一下,当我们单击登录按钮的时候,页面中会出现一个登录浮窗,而这个登录浮窗是唯一的,无论单击多少 次登录按钮,这个浮窗都只会被创建一次,那么这个登录浮窗就适合用单例模式来创建。
优缺点优点:创建对象和管理单例的职责被分布在两个不同的方法中
实现 1. 我们的第一个单例var instance = null var getInstance = function(arg) { if (!instance) { instance = arg } return instance } var a = getInstance("a") var b = getInstance("b") console.log(a===b)
这种定义一个全局变量的方式非常不优雅,也不好复用代码
2. 利用闭包实现单例var Singleton = function( name ){ this.name = name; }; Singleton.getInstance = (function(){ var instance = null; return function( name ){ if ( !instance ){ instance = new Singleton( name ); } return instance; } })(); var a = Singleton.getInstance("a") var b = Singleton.getInstance("b") console.log(a===b)
有些同学可能对闭包不大理解,下面用函数实现一下
3. 利用函数实现单例function Singleton(name) { this.name = name this.instance = null } Singleton.getInstance = function(name) { if (!this.instance) { this.instance = new Singleton(name) } return this.instance } var a = Singleton.getInstance("a") var b = Singleton.getInstance("b") console.log(a===b)
2,3这两种方式也有缺点,就是我们必须调用getInstance来创建对象,一般我们创建对象都是利用new操作符
4. 透明的单例模式var Singleton = (function() { var instance Singleton = function(name) { if (instance) return instance this.name = name return instance = this } return Singleton })() var a = new Singleton("a") var b = new Singleton("b") console.log(a===b)
这中方法也有点缺点:不符合单一职责原则,这个对象其实负责了两个功能:单例和创建对象
下面我们分离这两个职责
5. 利用代理实现单例var People = function(name) { this.name = name } var Singleton = (function() { var instance Singleton = function(name) { if (instance) return instance return instance = new People(name) } return Singleton })() var a = new Singleton("a") var b = new Singleton("b") console.log(a===b)
这中方法也有点缺点:代码不能复用。如果我们有另外一个对象也要利用单例模式,那我们不得不写重复的代码
6. 提供通用的单例var People = function(name) { this.name = name } var Singleton = function(Obj) { var instance Singleton = function() { if (instance) return instance return instance = new Obj(arguments) } return Singleton } var peopleSingleton = Singleton(People) var a = new peopleSingleton("a") var b = new peopleSingleton("b") console.log(a===b)
到这里已经比较完美了,等等这只是es5的写法,下面我们用es6来实现一下
7. es6单例模式class People { constructor(name) { if (typeof People.instance === "object") { return People.instance; } People.instance = this; this.name = name return this; } } var a = new People("a") var b = new People("b") console.log(a===b)比较以上几种实现
用全局变量的第1种方法,应该摒弃
用闭包实现的第2种方式,instance 实例对象总是在我们调用 Singleton.getInstance 的时候才被创建,应该摒弃
其他方式都是惰性单例(在需要时才创建)
js的特殊性我们都知道:JavaScript 其实是一门无类(class-free)语言,,生搬单例模式的概念并无意义。
单例模式的核心是确保只有一个实例,并提供全局访问。
我们可以用一下几种方式来另类实现
1. 全局变量比如var a = {},这时全局就只有一个a对象
但全局变量存在很多问题,它很容易造成命名空间污染,我们用以下两种方式解决
var namespace1 = { a: function () { alert(1); }, b: function () { alert(2); } };
另外我们还可以动态创建命名空间
var MyApp = {}; MyApp.namespace = function (name) { var parts = name.split("."); var current = MyApp; for (var i in parts) { if (!current[parts[i]]) { current[parts[i]] = {}; } current = current[parts[i]]; } }; MyApp.namespace("event"); MyApp.namespace("dom.style"); console.dir(MyApp); // 上述代码等价于: var MyApp = { event: {}, dom: { style: {} } };3. 闭包
var user = (function () { var __name = "sven", __age = 29; return { getUserInfo: function () { return __name + "-" + __age; } } })();例子 登录框
下面我们来实现一个点击登录按钮弹出登录框的例子
粗糙的实现上面这种方式如果用户没有点击登录按钮,也会在一开始就创建登录框
改进这种方式每次点击按钮都会创建一个登录框
再改进var createLoginLayer = (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("loginBtn").onclick = function () { var loginLayer = createLoginLayer(); loginLayer.style.display = "block"; };
这种方式不够通用,不符合单一职责原则
再再改进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"; }; //下面我们再试试创建唯一的iframe 用于动态加载第三方页面: var createSingleIframe = getSingle(function () { var iframe = document.createElement("iframe"); document.body.appendChild(iframe); return iframe; }); document.getElementById("loginBtn").onclick = function () { var loginLayer = createSingleIframe(); loginLayer.src = "http://baidu.com"; };
至此已经完美
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/100608.html
摘要:什么是设计模式设计模式是一种能够被反复使用,符合面向对象特性的代码设计经验的总结,合理的使用设计模式能够让你得代码更容易维护和可靠设计模式的类型共分为创建型模式,结构型模式,行为型模式三种创建型模式创建型模式是对一个类的实例化过程进行了抽象 什么是设计模式 设计模式是一种能够被反复使用,符合面向对象特性的代码设计经验的总结,合理的使用设计模式能够让你得代码更容易维护和可靠设计模式的类型...
摘要:什么是单例模式单例模式是一种十分常用但却相对而言比较简单的单例模式。对象就是单例模式的体现。总结单例模式虽然简单,但是在项目中的应用场景却是相当多的,单例模式的核心是确保只有一个实例,并提供全局访问。 1. 什么是单例模式? 单例模式是一种十分常用但却相对而言比较简单的单例模式。它是指在一个类只能有一个实例,即使多次实例化该类,也只返回第一次实例化后的实例对象。单例模式不仅能减少不必要...
阅读 631·2021-11-15 11:39
阅读 2845·2021-10-08 10:04
阅读 3239·2019-08-30 10:57
阅读 2972·2019-08-26 13:25
阅读 1860·2019-08-26 12:14
阅读 2605·2019-08-23 15:27
阅读 2968·2019-08-23 15:18
阅读 1746·2019-08-23 14:26