前言
本系列为阅读曾探的《JavaScript设计模式与开发实践》一书所做的读书笔记,大部分内容摘自原书,加入了部分个人理解。
单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式在 js 开发中的应用场景:登录弹窗(一个网站只应该有一个登录弹窗,多次点击也不会出现多个)。
Java语言下单例模式的实现(饿汉单例模式)
|
|
JS 语言下单例模式的实现
模仿 java 语言的简单实现
|
|
其中,getInstance 方法也可以使用闭包实现。
|
|
这种方法缺点很明显,使用者必须知道 Singleton 是单例类,并且获取对象不能通过 new 的方式。
透明化实现
|
|
通过自执行的匿名函数返回 Singleton 构造方法,并且使用闭包保证了 instance 的唯一性。
但这样的代码比较复杂,并且 CreateDiv 的构造函数负责了创建对象、保证 instance 唯一两个功能,违背了单一职责原则。
使用代理实现单例模式
从上述代码中移除管理单例的代码:
|
|
引入代理类:
|
|
这也是缓存代理的一个应用。
js 语言的单例模式
前面几种单例模式的实现方式,是接近传统面向对象语言的实现,从“类”中创建单例对象。但 JavaScript 其实是一门无类(class-free)语言,所以不需要像 java 等面向对象语言的方式来实现单例模式。
单例模式的核心是确保只有一个实例,并提供全局访问。在JavaScript 中创建对象的方法非常简单,既然只需要一个“唯一”的对象,那么不需要为它先创建一个“类”。
在原书中,使用全局变量当作单例使用,例如:
|
|
但是全局变量很容易造成命名空间污染。书中介绍了几种可以相对降低全局变量带来的命名污染问题的方式:
使用命名空间
最简单的方法依然是用对象字面量的方式,减少全局变量的数量:
|
|
动态地创建命名空间(引自Object-Oriented JavaScrtipt 一书):
|
|
使用闭包封装私有变量
把一些变量封装在闭包的内部,只暴露一些接口跟外界通信:
|
|
个人认为在支持 ES6 的条件下,可以使用 let 声明变量,进一步保证对象的唯一性,避免被覆盖的问题。
惰性单例
惰性单例指的是在需要的时候才创建对象实例,如上述 js 实现单例模式的简单方法。
举例,登录浮窗的实现,点击按钮后才生成浮窗,并且一个页面只能存在一个。
实现代码:
|
|
单例模式还可以应用在 click 事件单次绑定。这里要注意书中对 jQuery 的 one 事件描述是不正确的,one 事件实现的是单次响应事件,而不是单次绑定事件。