欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

深入理解 JavaScript 单例模式 (Singleton Pattern)

程序员文章站 2022-06-27 21:54:30
概念 单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。 核心:确保只有一个实例,并提供全局访问。 实现思路 一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常命名为 );当我们调用这个方法时,类持有的引用不为 ......

概念

单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。

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

实现思路

一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常命名为getintance);当我们调用这个方法时,类持有的引用不为空则返回这个引用,如果为空须创建该类实例并将实例的引用赋予该类保持的引用;同时将该类的构造函数定义为私有方法,那么其他环境就无法通过调用该类的构造函数来实例化该类的对象,只能通过该类提供的静态方法得到该类唯一的实例。

实现 java 语言中的单例模式

  public class singleton {
      private static final singleton {
          private singleton() { };

          public static singleton getinstance {
              if (instance == null) {
                  synchronized(singleton.class) {
                      if(instance = null) {
                         instance = new singleton()
                      }
                  }

              }
              return instance;
          }
      }
  }

实现 javascript 语言中的单例模式

let singleton = function(name){
    this.name = name;
}
singleton.prototype.getname = function() {
    console.log(this.name)
}
singleton.getinstance = (function() {
   let instance;
   return function(name) {
       if(instance) return instance;
       return instance = new singleton(name)
   }
})()
let s1 = singleton.getinstance('owen'); // singleton {name: "owen"}
let s2 = singleton.getinstance('guowen'); // singleton.getinstance('guowen');
s1 === s2 // true

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

应用

命名空间

使用命名空间可以降低全局变量带来的命名污染;
最简单的方法是对象字面量

const globalweb = {
    a() {},
    b() {}
    // ...
}

或者使用闭包

let singleton = (function(){
    let instance;
    let init = function() {
    let name = 'owen';
        return {
            name,
            data(){
                return {}
            },
            method:{ }
        }
    }
    return {
        getinstance() {
            if(instance) return instance;
            return instance = init()
        }
    }
}())
let app = singleton.getinstance() // {name: "owen", data: ƒ, method: {…}}

惰性单例

惰性单例指在需要的时候才创建对象实例,在实现开发中非常有用,即目标对象只有在使用的时候才被创建,而不是页面加载好时创建。

模态框示例

点击一个按钮弹窗一个模态框,很明显页面是唯一的,一次不会弹窗多个模态框的情况

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>modal box</title>
    <style>
    * {
        margin: 0;
        padding:0;
    }
   html{
   width:100%;
   height:100%;
   }
    .owen {
        width:30%;
        height:30%;
        margin:10% auto;
    }
    #modal {
        width:100%;
        height:100%;
        position:fixed;
        left:0;
        top:0;
        background: rgba(0, 0, 0, 0.52);
        display:none;
    }
    .main{
        width:30%;
        height:30%;
        margin:10% auto;
        text-align: center;
        background-color: #b0e8ff;
    }
    </style>
</head>
<body>
   <div class="owen">
        <button>owen</button>
   </div>
    <div id="modal">
        <div class="main">
          <div>
                我是弹框
          </div>
        </div>
    </div>
</body>
<script>

window.onload = function(){
    let openmodal = document.queryselector("button")
    let modal = document.queryselector("#modal")
    openmodal.addeventlistener('click',function(){
       modal.style.display = 'block'
    })
}

</script>
</html>

第一种方法是在页面加载完成时创建好这个弹框,一开始就是隐藏的,只有点击按钮的时候才显示,这种方式有一个问题,就是我们进入页面,只是看看其他内容,不做任何操作;这样就造成资源浪费

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>modal box</title>
    <style>
    * {
        margin: 0;
        padding:0;
    }
   html{
   width:100%;
   height:100%;
   }
    .owen {
        width:30%;
        height:30%;
        margin:10% auto;
    }
    #modal {
        width:100%;
        height:100%;
        position:fixed;
        left:0;
        top:0;
        background: rgba(0, 0, 0, 0.52);
    }
    .main{
        width:30%;
        height:30%;
        margin:10% auto;
        padding:20px;
        text-align: right;
        background-color: #b0e8ff;
        position:relative;
    }
    .main div {
        text-align: center;
    }
    .main span {
        display: inline-block;
        padding:5px;
        cursor:pointer;
    }
    </style>
</head>
<body>

    <div class="owen">
        <button>点我</button>
    </div>

</body>
<script>
window.onload = function(){
    init()
}
function init() {
    let openmodal = document.queryselector("button")
    let createmodal =( function() {
        let flag;
        // 生成 modal 容器
        let div = document.createelement('div')
        div.id = "modal"
        div.style.display = "none";
        return function() {
            if(flag) return div;
            flag = true;
            let fra = document.createdocumentfragment();
            // 添加 modal 内容
            els = `<div class="main">
                    <span class="close">×</span>
                        <div>
                            我是弹框
                        </div>
                    </div>
                    `
            div.innerhtml = els;
            fra.appendchild(div)
            document.body.appendchild(fra)
            // 关闭 modal
            let close = document.queryselector('.close')
            close.addeventlistener('click',function(){
                flag = false;
                document.body.removechild(div)
            })

            return div
        }
    }())
    // 显示 modal
    openmodal.addeventlistener('click',function(){
       createmodal().style.display = "block";
    })
}
</script>
</html>

第二种方法,只执行一次dom的创建修改操作,不用频繁的创建和删除节点,提高资源利用率;

参考资料

《javascript设计模式与开发实践》
基维

大叔