写点什么

【设计模式 - 前端】单例模式深刻理解和实现

作者:归子莫
  • 2022 年 8 月 11 日
    广东
  • 本文字数:2639 字

    阅读完需:约 9 分钟

【设计模式-前端】单例模式深刻理解和实现

【设计模式-前端】单例模式深刻理解和实现

引言

内容速递:看了本文您能了解到的知识


1、什么是单例模式

一句话介绍:保证类的实例只有一个

1.1、简述前端的类

说到类,JS 在 ES6 提供了更接近面向对象语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。


注意:JavaScript 本质上是基于对象的语言

1.2、类是语法糖

其实,ES6 的 Class 可以看作只是 Function 的语法糖,它的绝大部分功能,ES5 的 Function 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

2、单例在前端的应用场景

单例模式在前端应用范围内有很多应用场景。

2.1、Vuex

很典型的单例模式的应用。Vuex 的 store 就是一个单例模式。采用了单一状态树,一个对象即为唯一数据源


可以简单看一下 Vuex 源码


let Vue ... export function install (_Vue) {  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 = _Vue
applyMixin(Vue)}
复制代码


可以看到 Vuex 在 install 的时候,判断是否有了唯一的 state。反之,如果没有这一段逻辑,在 Vue 中使用的时候


// 安装插件Vue.use(Vuex)
...(Vuex操作)
// 再次安装Vue.use(Vuex)
复制代码


再次安装的时候,唯一数据源 store 被重新生成,中间的 Vuex 操作就没有了

2.2、Redux

Redux 提供的全局的 store,和 Vuex 一样,必须是一个单例模式,不然每个组件各玩各的,如何实现数据协调同步呢。

2.3、全局组件

在前端中有一些全局组件,例如:创建全局唯一的对话框实例、记录日志信息全局唯一实例、登录弹窗、购物车等等。


这些组件都有一个特点,只有一个实例,状态唯一。

2.4、import

在 ES6 中,import 引入的模块是会自动执行的,但是有的时候我们可能会重复引入一个模块,但是这个时候不会执行多次,因为 import 就用到了 SIngleton 模式。

2.5、更多

还想看吗?可重点不是列举额,那这里也不多列举了,只能给你展示更多了!

3、单例的实现

3.1、思路

思路很简单,那就是一个类只有一个实例

3.2、实现

那怎么做到一个类只有一个实例?


去获取一个类的实例之前,去判断一下这个实例是否存在,如果存在直接把这个实例返回,那这样,不就是一个类只有一个实例了吗?


一个正常的类


每次 new 出来的实例都是不一样的


class SingleItem {  show() {    console.log('我是一个单例')  }}
const s1 = new SingleItem()const s2 = new SingleItem()
console.log(s1 === s2)// false
复制代码


借助 Class 和 static 实现单例


class SingleItem {
static instance
show() { console.log('我是一个单例') }
static getInstance() { return SingleItem.instance || (SingleItem.instance = new SingleItem()) }}
const s1 = SingleItem.getInstance()const s2 = SingleItem.getInstance()
console.log(s1 === s2)// true
复制代码

4、单例的优点与弊端

4.1、优点

  • 在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就 防止其它对象对自己的实例化,确保所有的对象都访问一个实例。

  • 由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。

  • 避免对共享资源的多重占用。

4.2、弊端

  • 由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。

  • 单例类的职责过重,在一定程度上违背了单一职责原则

  • 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。

5、单例实战

5.1、实现一个 Storage

听说是一个面试题!


问题描述:


实现一个 Storage,让该对象成为单例对象,可以基于 localStorage 实现。


思路:


1、获取实例


2、实例唯一


代码:


class Storage {
static instance
static getInstance() { return Storage.instance || (Storage.instance = new Storage()) }
getItem(key) { return localStorage.getItem(key) }
setItem(key, value) { localStorage.setItem(key, value) }}
复制代码


测试一下:


const s1 = Storage.getInstance()const s2 = Storage.getInstance()
s1.setItem('name', 'aaa')
// 测试两个的实例是否为同一个s1.getItem('name') // aaaconsole.log(s1.getItem('name'))s2.getItem('name') // aaaconsole.log(s2.getItem('name'))
console.log(s1 === s2)// true
复制代码

5.2、实现一个全局的 Modal 框

面试题+1


问题描述:


用单例模式写一个全局的 Modal 框


思路:


1、获取实例


2、实例唯一


这里也可以通过闭包来实现


代码:


<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <meta http-equiv="X-UA-Compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>单例Modal框</title></head><body>
<div id="openModal">打开Modal框</div> <div id="closeModal">关闭Modal框</div> </body>
<script> // 实现Modal框 const Modal = (function() { let modal = null return function() { if (!modal) { modal = document.createElement('div') modal.innerHTML = '我是Modal框' modal.style.display = 'none' document.body.appendChild(modal) } return modal } })()
document.getElementById('openModal').addEventListener('click', function() { const modal = new Modal() modal.style.display = 'block' })
document.getElementById('closeModal').addEventListener('click', function() { const modal = new Modal() modal && (modal.style.display = 'none') })</script>
</html>
复制代码

总结

慢慢开发的年龄大了,就越想搞点新玩意,但是编程的思维却越来越需要有足够的长进。最近要做一个 JS-SDK,单例的思想值得好好琢磨琢磨!

博客说明与致谢

文章所涉及的部分资料来自互联网整理,其中包含自己个人的总结和看法,分享的目的在于共建社区和巩固自己。

引用的资料如有侵权,请联系本人删除!

感谢万能的网络,W3C,菜鸟教程等!

感谢勤劳的自己个人博客GitHub学习GitHub

公众号【归子莫】,小程序【子莫说】

如果你感觉对你有帮助的话,不妨给我点赞鼓励一下,好文记得收藏哟!关注我一起成长!

幸好我在,感谢你来!


发布于: 刚刚阅读数: 6
用户头像

归子莫

关注

笔杆揭不起,绘写不出青烟别春泥! 2022.01.12 加入

信息安全工程师,现职前端工程师的全栈开发,三年全栈经验。专究于前后端开发基础与实战方向,偶尔的兴趣是安全方向,现在在学习前端3D与VR方向。微信公众号:归子莫。甚至全网可搜归子莫!

评论

发布
暂无评论
【设计模式-前端】单例模式深刻理解和实现_前端_归子莫_InfoQ写作社区