资讯专栏INFORMATION COLUMN

js设计模式--单例模式

CloudwiseAPM / 1626人阅读

摘要:文章系列设计模式单例模式设计模式策略模式设计模式代理模式概念单例模式的定义是保证一个类仅有一个实例,并提供一个访问它的全局访问点。在开发中,单例模式的用途同样非常广泛。

前言

本系列文章主要根据《JavaScript设计模式与开发实践》整理而来,其中会加入了一些自己的思考。希望对大家有所帮助。

文章系列

js设计模式--单例模式

js设计模式--策略模式

js设计模式--代理模式

概念

单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

UML类图

场景

单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏 览器中的 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种方法,应该摒弃

用闭包实现的第2种方式,instance 实例对象总是在我们调用 Singleton.getInstance 的时候才被创建,应该摒弃

其他方式都是惰性单例(在需要时才创建)

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;
      }
    }
  })();
例子 登录框

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

粗糙的实现



  




上面这种方式如果用户没有点击登录按钮,也会在一开始就创建登录框

改进



  



这种方式每次点击按钮都会创建一个登录框

再改进
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";
  };

至此已经完美

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

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

相关文章

  • JS 单例模式

    摘要:但是如何在对构造函数使用操作符创建多个对象的时候仅获取一个单例对象呢。单例的实例引用单例构造函数单例私有属性和方法暴露出来的对象改进之前在构造函数中重写自身会丢失所有在初始定义和重定义之间添加到其中的属性。 1. 单例模式 单例模式 (Singleton) 的实现在于保证一个特定类只有一个实例,第二次使用同一个类创建新对象的时候,应该得到与第一次创建对象完全相同的对象。当创建一个新对象...

    姘存按 评论0 收藏0
  • 浅谈js单例模式

    摘要:单例模式说到单例设计模式,中经常使用的单例模式通常分两种,懒汉模式和饿汉模式懒汉模式简单写了下私有化构造函数在获取实例的方法中返回实例化对象虽然很多大佬都写过啦,但是小生为了加深记忆便再写一遍虽然实现了单例模式,但是未考虑到线程安全,多个线 java单例模式 说到单例设计模式,Java中经常使用java的单例模式通常分两种,懒汉模式和饿汉模式 懒汉模式 class singleDemo...

    draveness 评论0 收藏0
  • js常用设计模式实现(一)单例模式

    摘要:什么是设计模式设计模式是一种能够被反复使用,符合面向对象特性的代码设计经验的总结,合理的使用设计模式能够让你得代码更容易维护和可靠设计模式的类型共分为创建型模式,结构型模式,行为型模式三种创建型模式创建型模式是对一个类的实例化过程进行了抽象 什么是设计模式 设计模式是一种能够被反复使用,符合面向对象特性的代码设计经验的总结,合理的使用设计模式能够让你得代码更容易维护和可靠设计模式的类型...

    EscapedDog 评论0 收藏0
  • 从ES6重新认识JavaScript设计模式(一): 单例模式

    摘要:什么是单例模式单例模式是一种十分常用但却相对而言比较简单的单例模式。对象就是单例模式的体现。总结单例模式虽然简单,但是在项目中的应用场景却是相当多的,单例模式的核心是确保只有一个实例,并提供全局访问。 1. 什么是单例模式? 单例模式是一种十分常用但却相对而言比较简单的单例模式。它是指在一个类只能有一个实例,即使多次实例化该类,也只返回第一次实例化后的实例对象。单例模式不仅能减少不必要...

    G9YH 评论0 收藏0

发表评论

0条评论

CloudwiseAPM

|高级讲师

TA的文章

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