首页IT科技js的单例模式(JavaScript中单例模式这样用)

js的单例模式(JavaScript中单例模式这样用)

时间2025-06-13 22:45:32分类IT科技浏览4349
导读:如果希望自己的代码更优雅、可维护性更高以及更简洁,往往离不开设计模式这一解决方案。...

如果希望自己的代码更优雅            、可维护性更高以及更简洁            ,往往离不开设计模式这一解决方案            。

在JS设计模式中                  ,最核心的思想:封装变化(将变与不变分离      ,确保变化的部分灵活         ,不变的部分稳定)                  。

单例模式

那么来说说第一个常见的设计模式:单例模式      。

单例模式保证一个类仅有一个实例                  ,并提供一个访问它的全局访问方式         ,为了解决一个全局使用的类频繁被创建和销毁                  、占用内存的问题         。

ES5中通过闭包

在ES5中      ,可以使用闭包(函数内部返回函数被外界变量所引用                  ,导致这个函数里面的变量无法被释放            ,就构建成闭包)来保存这个类的实例                  。

var Singeton = (function(){ var instance; function User(name,age){ this.name=name; this.age=age; } return function(name,age){ if(!instance){ instance = new User(name,age) } return instance } })()

此时这个实例一旦生成   ,每次都是返回这个实例                  ,且不会被修改               ,可以看到下面的代码,当给 User 对象初始赋值 name:alice               ,age:18 时                  ,以后再赋值便无效了   ,以及每次返回都是初始的实例对象         。

ES6中使用类的静态属性

以上代码使用ES6语法来实现            ,通过类的静态属性来保存唯一的实例对象      。

class Singeton { constructor(name,age){ if(!Singeton.instance){ this.name = name; this.age = age; Singeton.instance = this; } return Singeton.instance; } }

创建方式仍然是一样的                  ,通过 new 关键字创建类的实例对象                  。

案例

那这样一种设计模式在开发中实际有什么用途呢?我们试想这样一个业务场景:访问网站时      ,很久没有操作页面         ,此时授权过期                  ,当我们点击页面上的任何一个地方         ,都会弹出一个登录框            。

那么这个登录框      ,是全局唯一的                  ,不会存在多份            ,也不会互相冲突   ,所以不需要每次都创建一份                  ,保留初始那一份就够了   。

提前创建节点

我们可能会想到首先在页面中提前创建节点               ,编写好页面样式,最后通过控制元素的 display 属性来达到显示和隐藏的效果                  。

<div class="modal">登录对话框</div> <button id="open">打开</button> <button id="close">关闭</button> <style> .modal { display: none; /* 其他布局代码省略 */ } </style> <script> document.querySelector("#open").onclick = function(){ const modal = document.querySelector(.modal) modal.style.display = block } </script>

这样可以完成需求               ,全局只有一个登录框                  ,每次都展示同一个               。但问题是dom元素从一开始它创建好并添加到body中   ,无论是否需要用到            ,如果有些场景不需要登陆                  ,那么这里初始渲染就会浪费空间。

单例模式

那如果不需要初始渲染      ,仅当需要时才使用         ,并且每次都返回同一个实例的单例模式应该如何实现呢?

我们可以这样处理

<!-- 去除class为modal的标签                  ,动态创建 --> <script> const Modal = (function(){ let instance = null return function(){ if(!instance){ instance = document.createElement("div") instance.innerHTML = "登录对话框" instance.className = "modal" instance.style.display = "none" document.body.appendChild(instance) } return instance } })() document.querySelector("#open").onclick = function(){ //创建modal         ,如果放在外面      ,一开始就会创建元素 const modal = Modal() //显示modal modal.style.display = "block" } document.querySelector("#close").onclick = function(){ const modal = Modal() modal.style.display = "none" } </script>

虽然上面的方式可以达到效果                  ,但是创建对象和管理单例的逻辑都放在了对象内部            ,是有些混乱的               。并且如果下次需要创建页面中唯一的 iframe   ,或者 script 标签                  ,就得将以上函数照抄一遍                  。

通用单例

首先拆分函数逻辑               ,将执行创建对象的逻辑拿出来

const createLayer = function(){ let div = document.createElement("div") div.innerHTML = "登录对话框" div.className = "modal" div.style.display = "none" document.body.appendChild(div); return div; } const Modal = (function(){ let instance = null return function(){ if(!instance){ instance = createLayer() } return instance } })()

以上修改后代码逻辑就更为清晰,但此时还不支持通用化的创建别的组件               ,这时候我们想想如何将创建单例的方法进行一些优化                  ,是否可以将单例需要执行的函数抽象化   。

const createSingle = (function(fn){ let instance; return function(){ return instance || ( instance = fn.apply(this, arguments)) } })()

这样改造后   ,如果存在创建 iframe 的方法            ,也可以直接使用            。

const createIframe = function() { const iframe = document.createElement(iframe); iframe.style.display = none; document.body.appendChild(iframe); return iframe } const singleIframe = createSingle(createIframe) document.querySelector("#open").onclick = function(){ const iframe = singleIframe() iframe.style.display = block }

实际应用

以上都是咱小打小闹的试用                  ,那再来看看社区中一些非常棒的实现吧~ 比如:React 中常用的状态管理工具 Redux 就使用到了单例模式      ,它有这样一些要求                  。

单一数据源:整个应用的 state 只存在于唯一一个 store 中      。 State 是只读的:不要直接改变 state 的值         ,唯一改变 state 的方法就是触发 action         。 reducer 是纯函数:需要编写纯函数 reducer 来修改 state 的值                  。

来看看 Redux 的源码                  ,为了便于阅读已删减部分逻辑判断和注释         ,可以看到通过 store 的 getState 方法每次获取闭包中的 currentState         。

单例模式在内存中只有一个实例      ,可以减少内存开支                  ,同时还能在系统设置全局的访问点            ,优化和共享资源      。

以上就是单例模式的相关介绍                  。更多有关 前端      、设计模式 的内容可以参考我其它的博文   ,持续更新中~

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
火车头采集器有什么用(火车头采集器——让图片采集如此简单) python怎么定义一个类(python中使用__slots__定义类属性)