需求: 实现一个登录的弹框
方案1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>单例模式</title>
</head>
<body>
<button id="btn">Login</button>
<script>
var loginLayer = (function () {
var div = document.createElement('div')
div.innerHTML = 'Login Comp'
div.style.display = 'none'
document.body.appendChild(div)
return div
})()
document.getElementById('btn').onclick = function () {
loginLayer.style.display = 'block'
}
</script>
</body>
</html>
缺点: 加载完成时候已经创建好弹框 只是隐藏起来了,造成资源的浪费
方案2
改造一下上面的方案1的代码,不使用立即执行函数了
每次只有点击按钮以后,才调用createLoginLayer
方法,创建一个div
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>单例模式2</title>
</head>
<body>
<button id="btn">Login</button>
<script>
var createLoginLayer = function () {
var div = document.createElement('div')
div.innerHTML = 'Login Comp'
div.style.display = 'none'
document.body.appendChild(div)
return div
}
document.getElementById('btn').onclick = function () {
var loginLayer = createLoginLayer()
loginLayer.style.display = 'block'
}
</script>
</body>
</html>
缺点:频繁创建销毁,占用资源
方案1和方案2都有缺点,怎么解决这个问题?就要引出单例模式的概念了:
简单来说,就是每次创建一个实例对象的时候,判断内存中是否已经有这个单例,有的话就返回,没有的话就创建,这就需要在内存中有一个标记,来标记是否存在这样的一个单例对象,所以我们想到了
闭包
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>单例模式3</title>
</head>
<body>
<button id="btn">Login</button>
<script>
var createLoginLayer = (function () {
var div
return function () {
if (!div) {
div = document.createElement('div')
div.innerHTML = 'Login Component'
div.style.display = 'none'
document.body.appendChild(div)
}
return div
}
})()
document.getElementById('btn').onclick = function () {
var loginLayer = createLoginLayer()
loginLayer.style.display = 'block'
}
</script>
</body>
</html>
内部的函数被保存到外部loginLayer
,这样在外部loginLayer
这里也能访问到函数createLoginLayer
里面的变量div,于是产生了闭包。
效果如下:
代码到这里还可以优化:
写代码有一种思想,单一职责
思想,我们用这个思想优化上述代码:
上述代码把形成单例和创建登录模块杂糅在一起了,我们这里用``单一职责```思想使这两个功能解耦
1.单例的职责:
var getSingle = function (fn) {
var result
return function () {
return result || (result = fn.apply(this, arguments))
}
}
2.创建登录模块职责
var createLogin = function () {
var div = document.createElement('div')
div.innerHTML = 'My-Login-Component'
div.style.display = 'none'
document.body.appendChild(div)
return div
}
结合到一起:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>单例模式4</title>
</head>
<body>
<button id="btn">Login</button>
<script>
// 1.单例职责(形成闭包)
var getSingle = function (fn) {
var result
return function () {
return result || (result = fn.apply(this, arguments))
}
}
// 2.创建登录模块职责
var createLogin = function () {
var div = document.createElement('div')
div.innerHTML = 'My-Login-Component'
div.style.display = 'none'
document.body.appendChild(div)
return div
}
var createSingleLogin = getSingle(createLogin)
document.getElementById('btn').onclick = function () {
var loginLayer = createSingleLogin()
loginLayer.style.display = 'block'
}
</script>
</body>
</html>