JS设计模式-单例模式
在java中,单例模式被定义为:保证一个类仅有一个实例,并提供一个访问它的全局访问点。这种设计模式在JavaScript中也同样适用,我们可以来保证总是有唯一的对象、方法或者是DOM元素。先来看个最简单的例子:
dom1 = document.createElement("div");
dom2 = document.createElement("div");
console.log(dom1 === dom2); // false
其实很显然,dom1
和dom2
并不是同一个元素,所以两者必然不同。在vue的开发中,状态管理VUEX就是一个最常见的单例模式,作为全局的状态,无论在哪里使用,都要保证它的唯一性,否则状态就不准确、不可信。不过在这里还是用dom元素来做说明,为了方便观看,我也会极简代码。
首先模拟一个登陆弹窗的功能:
<html >
<body>
<button onclick="login()">登录</button>
</body>
</html>
<script>
function createDom() {
dom = document.createElement("div");
dom.innerHTML = "我是登录";
document.body.appendChild(dom);
}
function login(params) {
createdom()
}
</script>
很显然这种实现方式,你点了多少次按钮,就会创建多少个DOM元素,换做弹窗的话,就有Windows XP下的错误弹窗一般了。那么单例模式就是为了解决这个问题,来使得无论点击多少次,都只会创建一次弹窗。
我们改造一下方法
function getSingle() {
let dom = null
return function () {
if (!dom) {
dom = document.createElement("div")
dom.innerHTML = "我是登录"
document.body.appendChild(dom)
}
return dom
}
}
const createdom = getSingle()
function login(params) {
createdom()
}
我们利用函数的作用域,创建了dom
用来保存状态,如果dom为空就创建新的元素,不然就直接返回。这回无论点击多少次,都只会出现一个div了。
但是这种方式也并不完美,我这次创建div
写了一个单例模式,我如果下次需要创建一个span
岂不是还要重新写?我们在开发中,都会尽量遵守单一职责原则,也就是一个函数只做一件事,那么我们稍加改造:
function getSingle(fn) {
let dom = null
return function() {
return dom || (dom = fn())
}
}
function createDiv() {
dom = document.createElement("div")
dom.innerHTML = "我是登录"
document.body.appendChild(dom)
return dom
}
const createdom = getSingle(createDiv)
function login(params) {
createdom()
}
首先我们改造了getSingle
方法,让它接受一个函数作为参数,其余没有变化,仍然是利用函数的作用域进行判断,dom为空就执行fn
函数,否则就返回dom
,这样我们就可以把创建元素的函数解耦出来单独声明,需要注意的是一定要加返回值,来让getSingle
保存状态。
很早就像写设计模式的内容,但是一直觉得无从下手,一方面是写的人很多,大部分写的比我的详细的多。二是害怕自己的理解不够深,会误导读者,总之先写一篇试试了,如果骂的多就不继续写下去了,如果反响还可以,我可能还会继续写别的设计模式。