博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入了解JavaScript设计模式系列-单例模式
阅读量:6820 次
发布时间:2019-06-26

本文共 1899 字,大约阅读时间需要 6 分钟。

前言

单例模式的定义是产生一个类的唯一实例,但js本身是一种“无类”语言。很多讲js设计模式的文章把{}当成一个单例来使用也勉强说得通。因为js生成对象的方式有很多种,我们来看下另一种更有意义的单例。

有这样一个常见的需求,点击某个按钮的时候需要在页面弹出一个遮罩层。

这个生成灰色背景遮罩层的代码是很好写的。

var createMask = function(){   return document.body.appendChild(document.createElement(div));}复制代码
$('button').click( function(){   Var mask  = createMask();   mask.show();})复制代码

问题是, 这个遮罩层是全局唯一的, 那么每次调用createMask都会创建一个新的div, 虽然可以在隐藏遮罩层的把它remove掉. 但显然这样做不合理。

再看下第二种方案, 在页面的一开始就创建好这个div. 然后用一个变量引用它。

var mask = document.body.appendChild(document.createElement('div'));$('button').click( function(){   mask.show();})复制代码

这样确实在页面只会创建一个遮罩层div, 但是另外一个问题随之而来, 也许我们永远都不需要这个遮罩层, 那又浪费掉一个div, 对dom节点的任何操作都应该非常吝啬。

如果可以借助一个变量. 来判断是否已经创建过div呢?

var mask;var createMask = function(){    if (mask){        return mask;    }     else{        mask = document,body.appendChild(document.createElement(div));        return mask;    }}复制代码

看起来不错, 到这里的确完成了一个产生单列对象的函数. 我们再仔细看这段代码有什么不妥。

首先这个函数是存在一定副作用的, 函数体内改变了外界变量mask的引用, 在多人协作的项目中, createMask是个不安全的函数. 另一方面, mask这个全局变量并不是非需不可. 再来改进一下。

var createMask = function(){  var mask;  return function(){       return mask || (mask = document.body.appendChild(document.createElement('div')))  }}()复制代码

用了个简单的闭包把变量mask包起来, 至少对于createMask函数来讲, 它是封闭的。

可能看到这里, 会觉得单例模式也太简单了. 的确一些设计模式都是非常简单的, 即使从没关注过设计模式的概念, 在平时的代码中也不知不觉用到了一些设计模式。 就像多年前我明白老汉推车是什么回事的时候也想过尼玛原来这就是老汉推车。

再回来正题, 前面那个单例还是有缺点. 它只能用于创建遮罩层. 假如我又需要写一个函数, 用来创建一个唯一的xhr对象呢? 能不能找到一个通用的singleton包装器。

js中函数是第一型, 意味着函数也可以当参数传递. 看看最终的代码。

var singleton = function(fn){    var result;    return function(){        return result || (result = fn.apply(this, arguments));    }}var createMask = singleton(function(){    return document.body.appendChild(document.createElement('div'));})复制代码

用一个变量来保存第一次的返回值, 如果它已经被赋值过, 那么在以后的调用中优先返回该变量。

而真正创建遮罩层的代码是通过回调函数的方式传人到singleton包装器中的。这种方式其实叫桥接模式。 关于桥接模式, 放在后面一点点来说。

然而singleton函数也不是完美的, 它始终还是需要一个变量result来寄存div的引用。 遗憾的是js的函数式特性还不足以完全的消除声明和语句。

转载地址:http://owmzl.baihongyu.com/

你可能感兴趣的文章
mysql
查看>>
11月15日云栖精选夜读:分布式服务框架Dubbo疯狂更新!阿里开源要搞大事情?...
查看>>
Druid数据库连接池就这么简单
查看>>
Python最假的库:Faker
查看>>
IDE 插件新版本发布,开发效率 “biu” 起来了
查看>>
阿里云安全肖力:安全基础建设是企业数字化转型的基石
查看>>
Redis 基础、高级特性与性能调优
查看>>
BZT52C15S资料
查看>>
Laravel Telescope入门教程(上)
查看>>
Linux配置ip 及网络问题排查
查看>>
AndroidStudio用Cmake方式编译NDK代码(cmake配置.a库)
查看>>
OSChina 周四乱弹 ——黑丝短裙java程序员同事
查看>>
设置iptables之后不能正常访问ftp解决方法
查看>>
移动端rem布局
查看>>
jsp与iframe跨域访问的一个方法
查看>>
ViewPager + Fragment 取消预加载
查看>>
BigDecimal 02 - 注意事项
查看>>
用js玩桌球游戏
查看>>
maven下运行jetty报错
查看>>
android 配置framework 使应用首选安装在SD卡
查看>>