Skip to content

Latest commit

 

History

History
207 lines (165 loc) · 4.52 KB

单例模式.md

File metadata and controls

207 lines (165 loc) · 4.52 KB

1.概念

解决需求:在程序运行过程中,程序只有一个构造对象,可以解决内存开销,共用相同数据

应用实例:全局存储的用户对象、vuex、全局模态框

实现方式:类对象的实现,闭包实现

2.实现

2.1基础实现

let instance = null;
function Single() {
  if (instance) {
    return instance;
  }

  instance = this;
}
const single1 = new Single();
const single2 = new Single();
console.log(single1 === single2);//true

2.2.使用全局变量容易被污染,这个时候使用闭包的实现,将变量封存在内部。

const createSingle = (function () {
  let instance = null;
  function Single() {
    if (instance) {
      return instance;
    }

    instance = this;
  }
  return new Single();
})();
const single1 = createSingle;
const single2 = createSingle;

console.log(single1 === single2);//true

2.3使用惰性函数实现,惰性函数执行一次,相当于执行到Single后把函数替换掉了的理解

function Single() {
  let instance = this;

  Single = function () {
    return instance;
  };
}

const single1 = new Single();
const single2 = new Single();
console.log(single1 === single2);//true

2.4 惰性函数会丢失原型对象

function Single() {
  let instance = this;

  let oldPrototype = Single.prototype;

  Single = function () {
    return instance;
  };

  Single.prototype = oldPrototype;
  instance = new Single();
  instance.constructor = Single;
  return instance;
}

const single1 = new Single();
const single2 = new Single();
console.log(single1 === single2);

2.5使用es6语法糖class实现单例模式

class Singleclass Single {
  static getInstance() {
    if (!Single.instance) {
      Single.instance = new Single();
    }

    return Single.instance;
  }
}

const single1 = Single.getInstance();
const single2 = Single.getInstance();

console.log(single1 === single2);

3.业务实例实现

3.1 全局模态框实现

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>单例模式弹框</title>
  </head>
  <style>
    #modal {
      height: 200px;
      width: 200px;
      line-height: 200px;
      position: fixed;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      border: 1px solid black;
      text-align: center;
    }
  </style>
  <body>
    <button id="open">打开弹框</button>
    <button id="close">关闭弹框</button>
  </body>
  <script>
    // 核心逻辑,这里采用了闭包思路来实现单例模式
    const Modal = (function () {
      let modal = null;
      return function () {
        if (!modal) {
          modal = document.createElement("div");
          modal.innerHTML = "我是一个全局唯一的Modal";
          modal.id = "modal";
          modal.style.display = "none";
          document.body.appendChild(modal);
        }
        return modal;
      };
    })();

    // 点击打开按钮展示模态框
    document.getElementById("open").addEventListener("click", function () {
      // 未点击则不创建modal实例,避免不必要的内存占用;此处不用 new Modal 的形式调用也可以,和 Storage 同理
      const modal = new Modal();
      modal.style.display = "block";
    });

    // 点击关闭按钮隐藏模态框
    document.getElementById("close").addEventListener("click", function () {
      const modal = new Modal();
      if (modal) {
        modal.style.display = "none";
      }
    });
  </script>
</html>

3.2 vuex简单实现

3.3 用户对象存储封装

// 定义Storage
class Storage {
    static getInstance() {
        // 判断是否已经new过1个实例
        if (!Storage.instance) {
            // 若这个唯一的实例不存在,那么先创建它
            Storage.instance = new Storage()
        }
        // 如果这个唯一的实例已经存在,则直接返回
        return Storage.instance
    }
    getItem (key) {
        return localStorage.getItem(key)
    }
    setItem (key, value) {
        return localStorage.setItem(key, value)
    }
}

const storage1 = Storage.getInstance()
const storage2 = Storage.getInstance()

storage1.setItem('name', '李雷')
// 李雷
storage1.getItem('name')
// 也是李雷
storage2.getItem('name')

// 返回true
storage1 === storage2