关于javascript:单例模式在前端的应用

单例模式

保障一个类仅有一个实例,并提供一个拜访它的全局拜访点。

个别能够用一个变量去标记,是否曾经为某个类创立过实例,如果是,则返回该实例,如果不是,则创立新的实例。

Vuex中的单例模式

其实不论是Vuex还是Redux,它们都采纳了单例模式。两者都用一个全局的惟一Store来存储所有状态。

在Vue我的项目中,咱们通过 Vue.use(Vuex) 来装置Vuex插件,该插件是一个对象模式,外部实现一个install办法。在装置插件时,会调用该办法,而后把store注入Vue实例中。
在install办法中采纳单例模式,管制store全局惟一。

let Vue // 利用闭包保留变量不被销毁
...

export function install (_Vue) {
  // 判断传入的Vue实例对象是否曾经被install过Vuex插件(是否有了惟一的state)
  if (Vue && _Vue === Vue) {
    if (process.env.NODE_ENV !== 'production') {
      console.error(
        '[vuex] already installed. Vue.use(Vuex) should be called only once.'
      )
    }
    return
  }
  // 若没有,则为这个Vue实例对象install一个惟一的Vuex
  Vue = _Vue
  // 将Vuex的初始化逻辑写进Vue的钩子函数里
  applyMixin(Vue)
}
  • 通过闭包保留标记量,不被销毁
  • 判断vue实例是否曾经注入过store,如果是间接返回
  • 若没有,则为这个实例对象创立一个惟一的Vuex,将Vuex的初始化逻辑写进Vue的钩子函数里。

思考:如果install函数中不采纳单例模式会产生什么?
若不应用单例模式,并且屡次调用 Vue.use(Vuex),那么会给Vue实例注入新的store,之前的数据都会清空。

单例模式的利用

实现一个Storage

形容:实现Storage,使得该对象为单例,基于 localStorage 进行封装。实现办法 setItem(key,value) 和 getItem(key)。

办法一:静态方法版

// 静态方法版
class Storage {
    static getInstance() {
        // 判断是否曾经有实例
        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', 'pengpeng');
storage2.setItem('name', 'linlin');

console.log(storage1.getItem('name')); // linlin
console.log(storage1 === storage2); // true

办法二:闭包版

// 闭包版
// 1、根底的StorageBase类,把getItem和setItem办法放在它的原型链上
function StorageBase() { };
StorageBase.prototype.getItem = function (key) {
    return localStorage.getItem(key);
};
StorageBase.prototype.setItem = function (key, value) {
    return localStorage.setItem(key, value);
}

// 2、创立构造函数,利用闭包以及立刻执行函数
const Storage = (function () {
    let instanse = null;
    return function () {
        if (!instanse) {
            instanse = new StorageBase();
        }
        return instanse;
    }
})();

const storage3 = new Storage();
const storage4 = new Storage();

storage3.setItem('age', 18);
storage4.setItem('age', 22);

console.log(storage3.getItem('age')); // 22
console.log(storage3 === storage4); // true

实现一个全局的模态框

<!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>

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理