Javascript设计模式-单例模式

361 阅读2分钟

本文基于《JavaScript设计模式与开发实践》一书,用一些例子总结一下JS常见的设计你模式与实现方法。 定义 保证一个类仅有一个实例,并提供一个访问它的全局访问点。

实现代理模式的单例

首先创建一个CreateDiv的构造函数 只负责创建div

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)
}

接下来引入代理类proxySingletonCreateDiv

var ProxysingletonCreateDiv = (function(){
 var instance;
  return function(html) {
    if (!instance) {
        instance = new CreateDiv(html)
    }
    return instance
  }
})()
var a = new ProxysingletonCreateDiv('test1');
var b = new ProxysingletonCreateDiv('test2');
console.log(a === b) // true

通用的惰性单例

惰性单例是指在需要的时候才创建对象实例, 而不像之前的代码那样,利用自执行行数在代码执行时就把对象实例创建。
当我们点击登录按钮时,页面中可能出现一个弹框,而这个弹框是唯一的,无论点击多少次登录按钮,弹框只会被创建一次,那么这种情况下就适合用单例模式来创建弹框。

<html>
  <body>
    <button id="loginBtn">登录</button>
  </body>
  <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>
</html>

当打开一个网站时,需要登录,但登录的弹窗只会在点击登录按钮的时候出现,甚至有的网站不需要登录就能直接浏览。那么很有可能将白白浪费一些DOM节点。这时我们并不需要再页面加载时就创建一个弹窗。 正确的打开方式可以用下面的方式实现。

登录

通用的惰性单例的实现就是要抽离所有的单例模式都是要实现的----控制只有一个对象。那么我们来看看控制只有一个对象的操作抽象出来是个什么样子:

var obj;
if (!obj) {
  obj = xxx
}

现在我们局把如何管理单例的逻辑从原来的代码抽离出来,这些逻辑被封装在getSingle函数内部,创建对象的方法fn被当成参数动态传入getSingle函数:

var getSingle = function(fn) {
    var result;
  return function(){
    return result || (result = fn.apply(this, arguments))
  }
}

接下来将用于创建登录浮窗的方法用参数fn的形式传入getSingle,我们可以不仅传入createLoginLayer,还能传入createScript、createIframe等。之后再让getSingle返回一个新的函数,并且用一个变量result来保存fn的计算结果。result变量因为保存在闭包中,它通用的惰性单例永远不会被销毁。在将来的请求中,如果resutlt已经被赋值,那么它将返回这个值。代码如下。

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'
}

至此我们实现了一个getSingle函数来帮我们实现只有一个实例对象的目的,并且将实例对象要做的职责独立出来,两个方法互不干扰。