单例模式
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
// 首先创建一个初始化的构造函数
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>
以上就是单例模式,单例模式其实包含两个内容,第一就是判断是否存在,第二就创建内容。两个内容结合就是单例模式。