js设想形式--单例形式

媒介

本系列文章重要依据《JavaScript设想形式与开辟实践》整顿而来,个中会加入了一些本身的思索。愿望对人人有所协助。

文章系列

js设想形式–单例形式

js设想形式–战略形式

js设想形式–代办形式

观点

单例形式的定义是:保证一个类唯一一个实例,并供应一个接见它的全局接见点。

UML类图

《js设想形式--单例形式》

场景

单例形式是一种经常运用的形式,有一些对象我们每每只须要一个,比方线程池、全局缓存、浏 览器中的 window 对象等。

在 JavaScript 开辟中,单例形式的用处一样异常普遍。试想一下,当我们单击登录按钮的时刻,页面中会涌现一个登录浮窗,而这个登录浮窗是唯一的,不管单击若干 次登录按钮,这个浮窗都只会被建立一次,那末这个登录浮窗就适合用单例形式来建立。

优瑕玷

长处:建立对象和治理单例的职责被散布在两个差别的要领中

完成

1. 我们的第一个单例


var instance = null
var getInstance = function(arg) {
  if (!instance) {
    instance = arg
  }
  return instance
}

var a = getInstance('a')
var b = getInstance('b')
console.log(a===b)

这类定义一个全局变量的体式格局异常不文雅,也不好复用代码

2. 应用闭包完成单例


var Singleton = function( name ){
  this.name = name;
};

Singleton.getInstance = (function(){
  var instance = null;
  return function( name ){
    if ( !instance ){
      instance = new Singleton( name );
    }
    return instance;
  }
})();
var a = Singleton.getInstance('a')
var b = Singleton.getInstance('b')
console.log(a===b)

有些同砚可能对闭包不大明白,下面用函数完成一下

3. 应用函数完成单例


function Singleton(name) {
  this.name = name
  this.instance = null
}

Singleton.getInstance = function(name) {
  if (!this.instance) {
    this.instance = new Singleton(name)
  }
  return this.instance
}

var a = Singleton.getInstance('a')
var b = Singleton.getInstance('b')
console.log(a===b)

2,3这两种体式格局也有瑕玷,就是我们必需挪用getInstance来建立对象,平常我们建立对象都是应用new操作符

4. 通明的单例形式

var Singleton = (function() {
  var instance
  Singleton = function(name) {
    if (instance) return instance
    this.name = name
    return instance = this
  }
  return Singleton
})()

var a = new Singleton('a')
var b = new Singleton('b')
console.log(a===b)

这中要领也有点瑕玷:不符合单一职责准绳,这个对象实在担任了两个功用:单例和建立对象

下面我们星散这两个职责

5. 应用代办完成单例

var People = function(name) {
  this.name = name
}

var Singleton = (function() {
  var instance
  Singleton = function(name) {
    if (instance) return instance
    return instance = new People(name)
  }
  return Singleton
})()

var a = new Singleton('a')
var b = new Singleton('b')
console.log(a===b)

这中要领也有点瑕玷:代码不能复用。假如我们有别的一个对象也要应用单例形式,那我们不能不写反复的代码

6. 供应通用的单例


var People = function(name) {
  this.name = name
}

var Singleton = function(Obj) {
  var instance
  Singleton = function() {
    if (instance) return instance
    return instance = new Obj(arguments)
  }
  return Singleton
}

var peopleSingleton = Singleton(People)

var a = new peopleSingleton('a')
var b = new peopleSingleton('b')
console.log(a===b)

到这里已比较圆满了,等等这只是es5的写法,下面我们用es6来完成一下

7. es6单例形式

class People {
    constructor(name) {
        if (typeof People.instance === 'object') {
            return People.instance;
        }
        People.instance = this;
        this.name = name
        return this;
    }
}
var a = new People('a')
var b = new People('b')
console.log(a===b)

比较以上几种完成

  1. 用全局变量的第1种要领,应当摒弃
  2. 用闭包完成的第2种体式格局,instance 实例对象总是在我们挪用 Singleton.getInstance 的时刻才被建立,应当摒弃
  3. 其他体式格局都是惰性单例(在须要时才建立)

js的特殊性

我们都晓得:JavaScript 实际上是一门无类(class-free)言语,,生搬单例形式的观点并没有意义。

单例形式的中心是确保只要一个实例,并供应全局接见。

我们能够用一下几种体式格局来另类完成

1. 全局变量

比方var a = {},这时候全局就只要一个a对象
但全局变量存在许多题目,它很轻易形成定名空间污染,我们用以下两种体式格局处理

2.运用定名空间

  var namespace1 = {
    a: function () {
      alert(1);
    },
    b: function () {
      alert(2);
    }
  };

别的我们还能够动态建立定名空间


  var MyApp = {};
  MyApp.namespace = function (name) {
    var parts = name.split('.');
    var current = MyApp;
    for (var i in parts) {
      if (!current[parts[i]]) {
        current[parts[i]] = {};
      }
      current = current[parts[i]];
    }
  };
  MyApp.namespace('event');
  MyApp.namespace('dom.style');
  console.dir(MyApp);
  // 上述代码等价于:
  var MyApp = {
    event: {},
    dom: {
      style: {}
    }
  };

3. 闭包

  var user = (function () {
    var __name = 'sven',
      __age = 29;
    return {
      getUserInfo: function () {
        return __name + '-' + __age;
      }
    }
  })();

例子

登录框

下面我们来完成一个点击登录按钮弹出登录框的例子

粗拙的完成

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

上面这类体式格局假如用户没有点击登录按钮,也会在一开始就建立登录框

革新


<html>

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

</html>

这类体式格局每次点击按钮都邑建立一个登录框

再革新


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

这类体式格局不够通用,不符合单一职责准绳

再再革新


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

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

  //下面我们再尝尝建立唯一的iframe 用于动态加载第三方页面:
  var createSingleIframe = getSingle(function () {
    var iframe = document.createElement('iframe');
    document.body.appendChild(iframe);
    return iframe;
  });
  document.getElementById('loginBtn').onclick = function () {
    var loginLayer = createSingleIframe();
    loginLayer.src = 'http://baidu.com';
  };

至此已圆满

    原文作者:aoping
    原文地址: https://segmentfault.com/a/1190000017717841
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞