singleton in Javascript

《parctical common lisp》的作者曾说,如果你需要一种模式,那一定是哪里出了问题。他所说的问题是指因为语言的天生缺陷,不得不去寻求和总结一种通用的解决方案。

不管是弱类型或强类型,静态或动态语言,命令式或说明式语言、每种语言都有天生的优缺点。一个牙买加运动员, 在短跑甚至拳击方面有一些优势,在练瑜伽上就欠缺一些。

术士和暗影牧师很容易成为一个出色的辅助,而一个背着梅肯满地图飞的敌法就会略显尴尬。 换到程序中, 静态语言里可能需要花很多功夫来实现装饰者,而js由于能随时往对象上面扔方法,以至于装饰者模式在js里成了鸡肋。

讲javascript设计模式的书还比较少. Pro javaScript Design Patterns.是比较经典的一本,但是它里面的例子举得比较啰嗦,所以结合我在工作中写过的代码,把我的理解总结一下。如果我的理解出现了偏差,请不吝指正。

一 单例模式

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

有这样一个常见的需求,点击某个按钮的时候需要在页面弹出一个遮罩层。比如web.qq.com点击登录的时候.

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

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函数来讲, 它是封闭的.

GOF里的23种设计模式, 也是在软件开发中早就存在并反复使用的模式. 如果程序员没有明确意识到他使用过某些模式, 那么下次他也许会错过更合适的设计 (这段话来自《松本行弘的程序世界》).

再回来正题, 前面那个单例还是有缺点. 它只能用于创建遮罩层. 假如我又需要写一个函数, 用来创建一个唯一的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的函数式特性还不足以完全的消除声明和语句.

时间: 2024-10-01 10:26:40

singleton in Javascript的相关文章

js设计模式--单体模式

单体模式 -单体模式(singleton)是javaScript中最基本最有用的设计模式之一. -这种模式提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码可以通过单一 的变量进行访问.通过确保单体对象只存在一份实例,你就可以确信自己的所有代码使用的都是 同样的全局资源. -简单单体 -闭包单体 -惰性单体 -分支单体 <script type="text/javascript" charset="utf-8"> // 单体模式(single

Learning JavaScript Design Patterns The Singleton Pattern

The Singleton Pattern The Singleton pattern is thus known because it restricts instantiation of a class to a single object. Classically, the Singleton pattern can be implemented by creating a class with a method that creates a new instance of the cla

JavaScript Patterns 7.1 Singleton

7.1 Singleton The idea of the singleton pattern is to have only one instance of a specific class. This means that the second time you use the same class to create a new object, you should get the same object that was created the first time. var obj =

JavaScript设计模式 Item 6 --单例模式Singleton

单例模式的定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池.全局缓存.浏览器的window对象.在js开发中,单例模式的用途同样非常广泛.试想一下,当我们单击登录按钮的时候,页面中会出现一个登录框,而这个浮窗是唯一的,无论单击多少次登录按钮,这个浮窗只会被创建一次.因此这个登录浮窗就适合用单例模式. 1.单例模式的使用场景 在使用一种模式之前,我们最好要知道,这种模式的使用场景.用了这么久的单例模式,竟全然不知!用它

JavaScript基础对象创建模式之单体/单例模式(Singleton)

首先,单例模式是对象的创建模式之一,此外还包括工厂模式.单例模式的三个特点: 1,该类只有一个实例 2,该类自行创建该实例(在该类内部创建自身的实例对象) 3,向整个系统公开这个实例接口 Java中大概是这个样子: class Singleton { //私有,静态的类自身实例 private static Singleton instance = new Singleton(); //私有的构造子(构造器,构造函数,构造方法) private Singleton(){} //公开,静态的工厂方

javascript设计模式之单例(singleton)模式

singleton模式限制了类的实例化次数只能有一次.singleton模式,该实例不存在的情况下,可以通过一个方法创建一个类来实现创建类的新实例:如果实例已经存在,它会简单的返回对象的引用.Singleton不同于静态类,它可以延迟实例化. 1.对象字面量实现 在javascript中实现单例模式有很多方式,其中最简单的就是对象字面量. var Singleton={ name:"vuturn", showName:function(){ console.log(this.name)

javascript设计模式-singleton(单例)模式

singleton(单例)模式被熟知的原因是因为它限制了类的实例化次数只能一次,单例模式,在该实例不存在的勤快下,可以通过一个方法创建一个类来实现创建类的新实例:如果实例已经存在,则会简单返回该对象的引用.单例模式不同于静态类(或对象),因为我们可以推迟它们的初始化,这通常是因为它需要一些信息,而这些信息在初始化期间可能无法获取,对于没有察觉到之前的引用代码,它们不会提供方便检索方法,这是因为它既不是对象,也不是由一个single返回的类,而是一个结构,在js中,singleton充当共享资源命

javascript设计模式——Singleton

单例模式指的是只能被实例化一次. 推荐阅读: http://blog.mgechev.com/2014/04/16/singleton-in-javascript/ 比较通用的一种Singleton模式 var mySingleton = (function () { // Instance stores a reference to the Singleton var instance; function init() { // Singleton // Private methods and

JavaScript高级程序设计---学习笔记(三)

函数表达式 定义函数的方式有两种:一种是函数声明,另一种是函数表达式. 关于函数声明,它的一个重要特征就是函数声明提升,意思是在执行代码之前会先读取函数声明所以可以把函数声明放在调用它的语句后面. 而函数表达式必须在调用它之前定义. 1.递归 递归函数是在一个函数通过名字调用自身的情况下构成的,如: function factorial(num){ if(num <= 1){ return 1; }else{ return num * factorial(num - 1); } } 这是一个经典