单例模式(Singleton)
单例模式的定义是:保证一个仅有一个实例,并提供一个访问它的全局访问点。
解析:即实现单例要满足两点。一、仅且有一个实例;二、有一个访问它的全局访问点。
使用场景:
- 线程池
- 全局缓存
- 登录框
- 事件只绑定一次 等等
一般我们想到的实现方法是:
javascript
const CreateDiv = (function () {
let instance;
const CreateDiv = function (html) {
if (instance) return instance; // 重点在于这步,判断是否有实例化一次
this.html = html;
this.init();
return instance = this;
}
CreateDiv.prototype.init = function () {
const div = document.createElement('div');
div.innerText = this.html;
document.body.appendChild(div);
}
return CreateDiv;
})();
const a = new CreateDiv('kim1');
const b = new CreateDiv('kim2');
console.log(a === b) // true
缺点:这个构造函数怪怪的。而且当我们需要实现一个 iframe
或者其他需求的时候,又要重新复制一次代码进行改写。
- 使用变量来判断
javascript
const createLoginLayer = (function () {
let div;
return function () {
if (!div) {
div = document.createElement('div');
div.innerHTML = '我是浮窗';
div.style.display = 'none';
document.body.appendChild(div);
}
return div;
}
})();
const popup = createLoginLayer();
缺点:违反了单一职责原则,创建对象和管理单例的逻辑都放在一个函数里,如果下一次业务不同,则又需要照抄一遍。
最终方案:将管理单例和创建对象分开开了,以后则需要传入不同的创建对象函数则可以实现单例模式。
javascript
function f(fn) {
let instance;
return function () {
return instance || (instance = fn.apply(this, arguments))
}
}
function a() {
const temp = new Object();
return temp;
}
const create = f(a)
console.log(create() === create()) // true
例如:实现一个登陆弹窗,当第一次点击登陆时,创建弹窗的对象,第二次则继续沿用之前创建好的对象。 PS:这里省略样式和弹窗的文本,只是简单的添加一个元素到 body 节点上。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="login">登陆</button>
<script>
document.getElementById('login').addEventListener('click', function () {
const loginDiv = login()
console.log(loginDiv)
})
function getSingle(fn) {
let instance;
return function () {
return instance || (instance = fn.apply(this, arguments))
}
}
function createDiv() {
const div = document.createElement('div');
div.innerHTML = '我是浮窗';
// TODO add style or edit HTML
document.body.appendChild(div);
return div
}
const login = getSingle(createDiv);
</script>
</body>
</html>