JavaScript中的单例模式

67 阅读2分钟

1. 定义与核心

单例模式的定义:

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

单例模式的核心是:

确保只有一个实例,并提供全局访问

2. JavaScript中的单例模式

全局变量不是单例模式,但在 JavaScript 开发中,我们经常会把全局变量当成单例来使用。

var a = {}

当用这种方式创建对象a 时,对象a 确实是独一无二的。如果a 变量被声明在全局作用域下,则我们可以在代码中的任何位置使用这个变量,全局变量提供给全局访问是理所当然的。这样就满足了单例模式的两个条件。

但是全局变量容易造成命名空间污染,以下几种方式可以相对降低全局变量带来的命名污染。

  1. 使用命名空间
var namespace1 = {
	a: function () {},
	b: function () {}
}
  1. 使用闭包封装私有变量
var user = (function(){ 
    var __name = 'sven', 
        __age = 29; 
 
    return { 
        getUserInfo: function(){ 
            return __name + '-' + __age; 
        } 
    } 
 
})();

我们用下划线来约定私有变量__name 和__age,它们被封装在闭包产生的作用域中,外部是访问不到这两个变量的,这就避免了对全局的命令污染

3. 惰性单例 *

惰性单例指的是在需要的时候才创建对象实例

场景:用户点击按钮创建一个弹窗 惰性单例模式创建弹窗

var createvar createLoginLayer = (function () {
  var div;
  return function () {
    // 通过立即执行函数产生闭包环境,判断当前是否创建div,如果已经创建直接返回之前创建的div
    if (!div) {
      div = document.createElement("div");
      div.innerHTML = "我是登录浮窗";
      div.style.display = "none";
      document.body.append(div);
    }
    return div;
  };
})();

document.querySelector("button").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.append(div);
  return div;
};

var createSingleLoginLayer = getSingle(createLoginLayer);

document.querySelector("button").onclick = function () {
  var loginLayer = createSingleLoginLayer();
  loginLayer.style.display = "block";
};

总结

在创建通用惰性单例函数时用到了闭包和高阶函数的概念,单例模式是一种简单但非常实用的模式,特别是惰性单例技术,再合适的时候才创建对象,并且只创建唯一的一个。更奇妙的是,创建对象和管理单例的职责被分布在两个不同的方法中,这两个方法组合起来才具有单例模式的威力。