资讯专栏INFORMATION COLUMN

JavaScript设计模式系列二:单例模式

SegmentFault / 692人阅读

摘要:什么时候需要用到单例模式呢其实单例模式在日常开发中的使用非常的广泛,例如各种浮窗像登录浮窗等,无论我们点击多少次,都是同一个浮窗,浮窗从始至终只创建了一次。这种场景就十分适合运用单例模式。

单例模式 什么是单例模式?

单例模式的定义:一个类仅有一个实例,并且可以在全局访问
什么时候需要用到单例模式呢?其实单例模式在日常开发中的使用非常的广泛,例如各种浮窗、像登录浮窗等,无论我们点击多少次,都是同一个浮窗,浮窗从始至终只创建了一次。这种场景就十分适合运用单例模式。

代码实现

我们创建一个“最老的人”的类,很明显,“最老的人”有且只有一个。这很符合我们单例模式的运用场景。我们先来看看完整代码:

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

oldestMan.prototype.getName = function () {
  console.log(this.name);
}
//引入一个代理函数和闭包的概念
var createOldestMan = (function () {
  var instance;
  return function (name) {
      if (!instance) {
         instance = new oldestMan(name);
      }
      return instance;
  }
})();

var personA = createOldestMan("holz");
var personB = createOldestMan("Amy");
personA.getName();  //  holz
personB.getName();  //  holz

我们可以在控制台上看到即使调用了两次createOldestMan并且赋了不一样的值,但两次getName()输出的都是第一次的“holz”。这就是单例模式。

代码看不太懂?没关系,现在给大家一一讲解。
首先我们创建了一个oldestMan类,创建了一个name属性。然后我们通过 prototype 给它添加一个getName()方法用来获取oldestMan的名字,相信到这里大家都是懂的,然后下面一段代码就是重点了,也比较难理解。我们打这段代码多带带拿出来将一下。

//引入一个代理函数和闭包的概念
var createOldestMan = (function () {
  var instance;
  return function (name) {
      if (!instance) {
         instance = new oldestMan(name);
      }
      return instance;
  }
})();

首先,我们不用管什么是代理函数,之所以叫它代理函数是因为它辅助我们实现单例模式的效果,这段函数第一个关键点是 createOldestMan() 是一个立即执行函数。立即函数在声明的时候就会立即执行,也就是在声明createOldestMan的时候这个函数就会执行,它会声明一个instance 变量,然后返回一个函数给createOldestMan。createOldestMan就相当于:

var createOldestMan = function (name) {
      if (!instance) {
         instance = new oldestMan(name);
      }
      return instance;
  }

第二个关键点是:这里利用了 闭包 的概念。

闭包是什么呢?我只需要记住当函数在定义时的语法作用域之外被调用,却还能访问定义时的语法作用域时,就是产生了闭包。

我们来看一下我们的代码,函数先定义了一个instance,然后再返回一个function(name),这个function(name)里面用到了instance变量。在正常情况下,在立即执行函数执行之后,instance变量就会被JavaScript的垃圾回收机制回收,但是因为function(name)被返回到了外部,而function(name)随时会被调用,随时会访问到instance变量,所以instance变量被保留在了内存中。这就产生了闭包。也就是说,function(name)被赋值给了外部的createOldestMan,在外部的语法作用域中执行,但还可以访问到定义时内部的语法作用域中的instance。

所以在 立即执行函数闭包 的作用下,instance只被申请了一次,也就是只有一个instance。也就是说,我们无论执行多少次createOldestMan("..."),instance只会是第一次的那个值。所以我们就可以判断instance是否已经被实例化了,来给instance赋值,如果instance已经被实例化,就返回instance。这就达到了一个类只有一个实例的效果。

通用的单例模式

我还可以改造一下代码,因为在开发中,我们可能不仅只有一个单例,所以我们应该让代码能够变得各个单例通用。我们应该在哪里改呢?没错,改代理函数。我们只需要把代理函数中的oldestMan()提取出来,改为以参数的形式传值,不局限于oldestMan()。

var singleObj;
var createSingleton = function (fn) {
  return function (text) {
    if (!singleObj) {
      singleObj = new fn (text);
    }
    return singleObj;
  }
}

这样我们就可以把单例作为参数传进去,用它实现不同的单例了。
完整代码是这样的:

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

oldestMan.prototype.getName = function () {
  console.log(this.name);
}

//一个通用的代理函数
var singleObj;
var createSingleton = function (fn) {
  return function (text) {
    if (!singleObj) {
    singleObj = new fn (text);
    }
    return singleObj;
  }
}

var person_1 = createSingleton(oldestMan)("holz");
var person_2 = createSingleton(oldestMan)("tom");
person_1.getName(); //holz
person_2.getName(); //holz

同样,即使再次调用createSingleton并传入不同的值,输出的依旧是第一次的“holz”。

总结

单例模式的定义:一个类仅有一个实例,并且可以在全局访问。
适用场景:其实单例模式在日常开发中的使用非常的广泛,例如各种浮窗、像登录浮窗等,无论我们点击多少次,都是同一个浮窗,浮窗从始至终只创建了一次。这种场景就十分适合运用单例模式。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90370.html

相关文章

  • javaScript设计模式系列) 单体模式

    摘要:使用构造函数如果被实例化过,就返回实例化的结果这种方式比较简洁,通过判断是否已经实例化过,但是也没啥安全性,如果在外部修改那很可能单例模式就被破坏了。 摘要 单体模式也有人称为单例模式,是javaScript 中最基本但又最有用的模式之一。 什么是单体 一讲到概念第一反应就是WTFshowImg(https://segmentfault.com/img/bVSUdx?w=600&h=3...

    ZoomQuiet 评论0 收藏0
  • JavaScript设计模式与开发实践系列单例模式

    摘要:本系列为设计模式与开发实践作者曾探学习总结,如想深入了解,请支持作者原版单例模式实现单例模式单例模式的定义是保证一个类仅有一个实例,并提供一个访问它的全局访问点。 本系列为《JavaScript设计模式与开发实践》(作者:曾探)学习总结,如想深入了解,请支持作者原版 单例模式 实现单例模式 单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。单例模式是一种常用的模式...

    Airy 评论0 收藏0
  • JavaScript设计模式与开发实践》读书笔记

    摘要:订阅模式的一个典型的应用就是后面会写一篇相关的读书笔记。享元模式享元模式的核心思想是对象复用,减少对象数量,减少内存开销。适配器模式对目标函数进行数据参数转化,使其符合目标函数所需要的格式。 设计模式 单例模式 JS的单例模式有别于传统面向对象语言的单例模式,js作为一门无类的语言。使用全局变量的模式来实现单例模式思想。js里面的单例又分为普通单例和惰性单例,惰性单例指的是只有这个实例...

    Panda 评论0 收藏0
  • JavaScript面试系列JavaScript设计模式之桥接模式和懒加载

    摘要:桥接模式的核心在于将抽象部分和它的实现部分分离,使它们都可以独立的变化。看起来这个版本已经很完美了不,它仍然有可以优化的空间,即题目提到的桥接模式。使用桥接模式的实现版本这个实现包含了三个函数。这个例子体现了桥接模式的作用。 我写的程序员面试系列文章 Java面试系列-webapp文件夹和WebContent文件夹的区别? 程序员面试系列:Spring MVC能响应HTTP请求的原因?...

    tracymac7 评论0 收藏0
  • 听飞狐聊JavaScript设计模式系列06

    本回内容介绍 上一回聊到JS中模拟接口,装饰者模式,掺元类,分析了backbone的继承源码,感觉还好吧! 介一回,偶们来聊一下在JS单例模式(singleton),单例模式其实运用很广泛,比如:jquery,AngularJS,underscore吖虾米的都是单例模式,来吧,直接开始咯: 1. 单例模式 保证一个类只有一个实例,从全局命名空间里提供一个唯一的访问点来访问该对象。其实之前写过的对象...

    hiYoHoo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<