Time Bomb Veela
  1. 1 Time Bomb Veela
  2. 2 One Last You Jen Bird
  3. 3 かかってこいよ NakamuraEmi
  4. 4 Life Will Change Lyn
  5. 5 Libertus Chen-U
  6. 6 Quiet Storm Lyn
  7. 7 Hypocrite Nush
  8. 8 Flower Of Life 发热巫女
  9. 9 The Night We Stood Lyn
  10. 10 Last Surprise Lyn
  11. 11 Warcry mpi
2017-03-26 18:25:45

设计模式——单例模式

弹出层是一个很常见的需求。在一个登录功能的设计中,我们都希望无论单击多少次登录按钮,这个弹窗都只会被创建一次。这里就适合用单例模式来创建。在JS中单例模式的应用也非常广泛,比如全局缓存,window对象等等。下面我就来谈谈在JS中单例模式的具体应用。


单例模式的创建

单例模式的核心是确保只有一个实例并提供全局访问。因为JS是一门无类语言(ES6新增类特性),就没必要利用构造函数来实现单例了,那么最简单的创建方式就是使用对象字面量的形式创建全局变量了。例子如下:

let singleton = {
  property1: a,
  property2: b,
  method1() {
    console.log('c');
  }
};

用这种方式创建单例时确实满足条件,但是全局变量存在很多问题。其一就是造成变量冲突,随时都可能被别人给覆盖。如果确实需要使用全局变量来创建,应该尽可能降低全局变量的污染。下面是两种常用方法。

1.使用命名空间

把单例都定义为命名空间的属性,可以减少变量和全局作用域打交道的机会。例子如下:

let namespace = {
  singleton: {
    property1: a 
    // ...
  }
}

2.闭包封装私有变量

将单例封装在闭包内部,只暴露接口与全局通信。

let user = (function() {
  let singleton = {
    property1: a
    // ...
  };
  return {
    getSingleton() {
      return singleton;
    }
  }
})();

惰性单例

如果我们想做到只有在使用的时候才初始化单例,那么该如何做呢?很简单,通过一个闭包存储单例即可。当然创建前必须对单例的唯一性做检查。

let createSingleton = (function() {
  let singleton;
  return function() {
    if (!singleton) { 
      //  单例创建逻辑
      singleton = {
        property1: a
        // ...
      }
    }
      return singleton;
  }
})();

进一步封装惰性单例

我们虽然创建了一个可用的惰性单例,但还存在下面一些问题:

  1. 这段代码违反了单一职责原则,创建单例和管理的逻辑混合在了一起。
  2. 如果下次我们需要创建其他的单例就必须重写整个函数。

我们需要把不变的部分和可变的部分隔离开。不变的部分是什么呢?实际上无论创建什么单例,管理的逻辑都是不变的。现在我们就可以把管理的逻辑抽出,将创建逻辑封装在一个函数里。代码如下:

let createSingleton = function(fn) {
  let singleton;
  return function() {
    if (!singleton) {
      singleton = fn.apply(this, arguments);
    }
    return singleton;
  }
}

在这个例子中我们无论用fn创建什么单例,都可以使用该例子来管理其唯一存在的功能。

小结

单例模式是我开始设计模式正式学习的第一个模式,虽然简单但也是非常实用的一个模式。今后一段时间内也会集中于设计模式文章的更新。

-- EOF --

添加在分类「 前端开发 」下,并被添加 「设计模式」 标签。

文章目录

 - [单例模式的创建](#单例模式的创建)
   - [1.使用命名空间](#1.使用命名空间)
   - [2.闭包封装私有变量](#2.闭包封装私有变量)
 - [惰性单例](#惰性单例)
 - [进一步封装惰性单例](#进一步封装惰性单例)
 - [小结](#小结)
回到首页