js设计模式——单例模式(读书JavaScript设计模式与开发实战笔记01)

单例模式

单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

	// 首先创建一个初始化的构造函数
    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>

以上就是单例模式,单例模式其实包含两个内容,第一就是判断是否存在,第二就创建内容。两个内容结合就是单例模式。

猜你喜欢

转载自blog.csdn.net/qq_28500793/article/details/88059572