最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript 单例模式

    正文概述 掘金(cherish爱学习78383)   2020-12-24   318

    【 设计模式就是在某种场合下对特定问题的简洁而又优雅的解决方案 】

    【 单例模式是各大模式中较为简单的,也是较为常用且很有用的模式。 在JS中尤为突出(每个对象字面量都可以看做是一个单例~) 】

    Singleton 单例模式(单态模式)

    1.定义 & 实现思路

    确保(一个类)仅有一个实例,并提供全局访问。

      单例就是保证一个类只有一个实例.
    
      实现思路:
        1.先判断实例存在与否,存在直接返回,如果不存在就创建了再返回.
        2.确保一个类只有一个实例对象。
    
      单例模式的思路是:
      一个类能返回一个对象的引用(并且永远是同一个)和一个获得该实例的方法(静态方法,通常使用 getInstance 名称)。
      当我们调用这个方法时,如果类持有的引用不为空就返回该引用,否者就创建该类的实例,并且将实例引用赋值给该类保持的那个引用再返回。
      同时将该类的构造函数定义为私有方法,避免其他函数使用该构造函数来实例化对象,只通过该类的静态方法来得到该类的唯一实例
    

    2.JavaScript 中单例模式的实现

    • 在JavaScript里,单例作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问该对象。

    • 在 js 开发中,我们经常会把全局变量当成单例来使用

    2.1 最简单的对象字面量

    再看单例模式的定义:【确保(一个类)仅有一个实例,并提供全局访问】

    var Sinleton = {
      attr: 1,
      show() {
        return this.attr
      }
    }
    var t1 = Sinleton
    var t2 = Sinleton
    console.log(t1 === t2) // true
    

    这样创建的对象 Sinleton ,

    1. 对象 Sinleton 确实是独一无二的。
    2. 如果 Sinleton 变量被声明在全局作用域下,那么我们可以在代码中的任何位置使用这个变量。

    这样就满足了单例模式的两个条件。

    优点:简单且实用

    缺点:

    1. 没有什么封装性,所有的属性方法都是暴露的。对于一些需要使用私有变量的情况就显得心有余而力不足了
    2. 对于 this 的问题也有一定弊端。

    2.2 构造函数内部判断

    function Singleton(name, age) {
      if(Singleton.unique) {
        return Singleton.unique
      }
      this.name = name
      this.age = age
      Singleton.unique = this
    }
    var t1 = new Singleton('cherish', 18)
    var t2 = new Singleton('silence', 18)
    console.log(t1 === t2) // true
    

    缺点:提出一个属性来做判断,但是也没有安全性,一旦外部修改了Construct的unique属性,那么单例模式也就被破坏了。

    2.3 使用闭包实现单例模式

    • 使用闭包将创建了的单例缓存起来
    var Singleton = (function() {
       function Construt() {
      }
      return new Construt()
    })()
    
    var t1 = Singleton
    var t2 = Singleton
    console.log(t1 === t2) // true
    

    与对象字面量方式类似。不过相对而言更安全一点,当然也不是绝对安全。 如果希望会用调用 single() 方式来使用,那么也只需要将内部的 return 改为

    var Singleton = (function() {
      var constance = null
      return function Construt() {
        if(!constance) {
          constance = this
        }
        return constance
      }
    })()
    
    var t1 = new Singleton('cherish', 18)
    var t2 = new Singleton('silence', 18)
    console.log(t1 === t2) // true
    

    3.传统方法实现单例模式

    3.1 实现一个简单的单例模式(不透明的)

    思路:用一个变量来标志 当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象

    class Singleton {
      constructor(name) {
        this.name = name;
        this.instance = null;
      }
      static getInstance(name) {
        if (!this.instance) {
          this.instance = new Singleton(name);
        }
        return this.instance;
      }
      getName() {
        return this.name;
      }
    }
    // getInstance:闭包 + 私有变量 的实现
    Singleton.getInstance = (function () {
      let instance = null;
      return function (name) {
        if (!instance) {
          instance = new Singleton(name);
        }
        return instance;
      };
    })();
    // 缺点:
    // 实现方式不透明。
    // 使用者必须通过需要研究代码的实现,才能知道要通过 Singleton.getInstance() 来获取对象。这与我们常见的用 new 关键字来获取对象有出入。
    

    3.2实现透明的的单例模式

    var Singleton = (function () {
      var instance = null;
      var createDiv = function (html) {
        if (!instance) {
          this.init(html);
        }
        return (instance = this);
      };
      createDiv.prototype.init = function (html) {
        var divObj = document.createElement("div");
        divObj.innerHTML = html;
        console.log(document.body.appendChild, divObj, html);
        document.body.appendChild(divObj);
      };
      return createDiv;
    })();
    var a = new Singleton("<span>aaa</span>");
    

    3.3 缓存代理实现可复用的单例模式

    功能拆解: 把 CreateDiv 独立出来, 而负责管理单例的逻辑移到代理类中,保证只有一个对象。 这样一来,CreateDiv 就变成了一个普通的类,它跟 代理 组合起来可以达到单例模式的效果。

    class Creatediv {
      constructor(html) {
        this.init(html);
      }
      init(html) {
        const divObj = document.createElement("div");
        divObj.innerHTML = html;
        document.body.appendChild(divObj);
      }
    }
    const SingletonProxy = (function () {
      let instance = null;
      return function (html) {
        if (!instance) {
          instance = new Creatediv(html);
        }
        return instance;
      };
    })();
    const a = new SingletonProxy("<span>我是一个span标签1</span>");
    const b = new SingletonProxy("<span>我是一个span标签2</span>");
    console.log(a === b);
    

    4.前端应用场景

    • 浏览器的 window 对象。在 JavaScript 开发中,对于这种只需要一个的对象,往往使用单例实现。

    • 遮罩层、登陆浮窗等。

    5.其他应用场景

    单例模式应用的场景一般发现在以下条件下:

    (1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。

    (2)控制资源的情况下,方便资源之间的互相通信。如线程池等。

    如:

    • Windows 的 Task Manager(任务管理器)、Recycle Bin(回收站)。

    • 网站的计数器,一般采用单例模式实现,否则难以同步。(计数器会告诉你关于你的网站的某个特定页面上的访问次数)。

    • 线程池。多线程的线程池的设计一般采用单例模式,这是由于线程池要方便对池中的线程进行控制。

    • 全局缓存等。

    6.避免/降低全局变量的命名污染

    全局变量容易造成命名空间污染。在大中型项目中,如果不加以限制和管理,程序中可能存在很多这样的变量。JavaScript 中的变量也很容易被不小心覆盖。
    作为普通的开发者,我们有必要尽量减少全局变量的使用,即使需要,也要把它的污染降到最低。以下几种方式可以相对降低全局变量带来的命名污染。
    

    开发中我们避免全局变量污染的通常做法如下:

    • 全局命名空间
    • 使用闭包

    它们的共同点是都可以定义自己的成员、存储数据。 区别是全局命名空间的所有方法和属性都是公共的,而闭包可以实现方法和属性的私有化。

    6.1使用命名空间

    6.1.1对象字面量

    var nameSpace = {
      a: function () {
        console.log("a");
      },
      b: function () {
        console.log("b");
      },
    };
    

    6.1.2.动态地创建命名空间

    var myApp = {};
    myApp.nameSpace = function (name) {
      var parts = name.split(".");
      let current = myApp;
      for (let i in parts) {
        if (!current[parts[i]]) {
          current[parts[i]] = {};
        }
        current = current[parts[i]];
      }
    };
    myApp.nameSpace("cherish.name");
    myApp.nameSpace("silence.age");
    // 上述代码等价于:
    var MyApp = {
      cherish: {
        name: {},
      },
      silence: {
        age: {},
      },
    };
    

    6.2 使用闭包封装私有变量

    var nameSpace = (function () {
      let _name = 'cherish'
      return {
        getInfo() {
          return _name
        }
      }
    })()
    console.log(nameSpace.getInfo());
    

    7.总结

    【 设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象 】

    【 在开发中经常会使用中间类,通过它来实现原类所不具有的特殊功能。———— 结合缓存代理,实现可复用的单例模式 】

    【 如果严格的只需要一个实例对象的类(虽然JS没有类的概念),那么就要考虑使用单例模式 】

    【 使用数据缓存来存储该单例,用作判断单例是否已经生成,是单例模式主要的实现思路 】

    参考

    JavaScript 设计模式之单例模式


    起源地下载网 » JavaScript 单例模式

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元