單例模式
單例模式:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
// 首先創建一個初始化的構造函數
var CreateDiv = function (html) {
this.html = html;
this.init();
}
CreateDiv.prototype.init = function () {
var div = document.createElement('div');
div.innerHTML = this.html;
document.body.appendChild(div);
}
// 依據單一職責原則 創建代理來實現單例
var ProxySingletonCreateDiv = (function () {
// 需要返回CreateDiv
var instance;
return function (html) {
if (!instance) {
instance = new CreateDiv(html);
}
return instance;
}
})();
var a = ProxySingletonCreateDiv('viven');
var b = ProxySingletonCreateDiv('kevin');
console.log(a===b); // true
惰性單例模式:只有在需要的時候纔會創建對象的實例,
例如一個登陸框,通常的解決方案是創建好一個登陸窗口,隱藏,等需要的時候點擊。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>惰性單例模式</title>
</head>
<body>
<button id="loginBtn">登錄</button>
<script>
var loginLayer = (function () {
var div = document.createElement('div');
div.innerHTML = '懸浮登錄框';
div.style.display = 'none';
document.body.appendChild(div);
return div;
})();
document.getElementById('loginBtn').onclick = function () {
loginLayer.style.display = 'block';
};
</script>
</body>
</html>
但是這樣有一個問題,就是浪費了不必要的DOM節點,因爲不一定會用的上,我們的要求是在需要的時候,創建這個對象。
我們可以改造一下,就是只有在點擊的時候才創建。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>惰性單例模式</title>
</head>
<body>
<button id="loginBtn">登錄</button>
<script>
var createLoginLayer = function () {
var 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';
};
</script>
</body>
</html>
這樣就只有在點擊的才創建,但是出現了每點擊一次就出現一個登陸框的BUG,這顯然不符合我們的需求,我們可以在創建的時候給它一個變量,當登錄框不存在的時候。則創建,當存在則不創建。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>惰性單例模式</title>
</head>
<body>
<button id="loginBtn">登錄</button>
<script>
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';
};
</script>
</body>
</html>
這樣就能解決多次創建的問題了,至於這裏爲什麼在createLoginLayer函數要用閉包,那是因爲我們要保持對div變量的引用,不然每次調用的時候都會重新初始化div,達不到單例的效果。
有的同學說直接把div變量放外面 行不行,當然行,但是我們學javascript都知道,要儘量減少全局變量的使用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>惰性單例模式</title>
</head>
<body>
<button id="loginBtn">登錄</button>
<script>
var div;
var createLoginLayer = 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';
};
</script>
</body>
</html>
上面雖然能解決問題,但是強烈不推薦。
雖然我們通過閉包解決的全局變量的問題,但是上面的寫法還是違背了單一職責原則,我們需要解耦。
依據上面的代碼,我們不難發現,其實包括了兩個功能,1、創建一個窗口。2、檢查是否創建。
// 檢查是否創建
var obj;
if (!obj) {
obj = xxx;
}
return obj;
var obj;
return obj||(obj=xxx)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>惰性單例模式</title>
</head>
<body>
<button id="loginBtn">登錄</button>
<script>
// 這裏檢查是否創建
var getSingle = function (fn) {
var result;
return function () {
return result || (result = fn.apply(this, arguments));
}
}
// 這個方法是創建div
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';
};
</script>
</body>
</html>
以上就是單例模式,單例模式其實包含兩個內容,第一就是判斷是否存在,第二就創建內容。兩個內容結合就是單例模式。