`
txf2004
  • 浏览: 6830871 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

《JavaScirpt设计模式》(4)——单例模式

 
阅读更多

1、简介

单例模式是JS中最基本但又最有用的模式之一。这种模式提供了一种将代码组织为一个逻辑单位的手段。通过确保单例对象只存在一份实例,你可以确保自己的所有代码使用的都是同样的全局资源。


2、最基本的单例

相对于其他语言,在JS中,创建一个单例无非是太容易了,最简单的单例实际上就是一个对象字面量,它把一批有一定关联的方法和属性组织在一起:

var Singleton = {   
   attr1: true,    
   attr2: 10,    
   method: function(){}
};

在这个例子中,所有成员都可以通过变量Singleton来访问。

Singleton.attr1 = false; var total = Singleton.attr2 + 5; var result = Singleton.method();

这个单例对象的成员可以被修改。这实际上违背了面向对象设计的一条原则:类可以被扩展,但不应该被修改。如果某些变量需要保护,那么可以用到文章(2)中的闭包方式。

并非所有对象字面量都是单体,如果它只是用来模拟关联数组或容纳数据的话,那就显然不是单例。如果它是用来组织一批相关方法和属性的话,那就可能是单例。其区别主要在于设计者的意图。


3、划分命名空间

单例对象由两个部分组成:包含着方法和属性成员的对象自身,以及用于访问它的变量。这个变量通常是全局性的,这是单例模式的一个要点。而单例对象的所有内部成员都被包装在这个对象中,所以它们不是全局性的,这些成员只能通过这个单例对象变量进行访问,因此在某种意义上,可以说它们被单例对象圈在了一个命中空间中。

为了无意中改写变量,最好的解决办法之一是用单例对象将代码组织在命名空间之中。命名空间还可以进一步分隔,可以定义一个用来包含自己的所有代码的全局对象:

/*Util namespace*/
var Util = {};  

Util.Event = {
    //事件命名空间,包括了事件处理的各种代码
};

Util.Error = {
    //存储一些错误处理代码
};
来源于外部的代码与Util这个变量发生冲突的可能性很小。如果真有冲突,其造成的问题会非常明显,所以很容易被发现。也许如果能像其他语言那样用一个 namespace函数或操作符来声明一个命名空间,这样能使得代码更容易组织,且更容易一目了然。当然在JS中可以模拟namespace,但是无法将代码像提供命名空间的语言那样组织在一个大括号中,我们还是必须通过对象和'.'运算符进行显示的成员的添加,不过通过模拟namespace带来的好处就是代码的易读性。以下模拟了namespace:

/*命名空间函数*/
var namespace = function(ns){
	if(typeof ns !== 'string'){
		throw new Error('namespace must be a string');
	}
	
	var ns_arr = ns.split('.'),
		s	   = ns_arr[0], pre_s,
		i      = 1;
	
	window[s] = window[s] || {};
	pre_s = window[s];
	
	for (len = ns_arr.length; i < len; ++i) {
		s = ns_arr[i];
		pre_s[s] = pre_s[s] || {};
		pre_s = pre_s[s];
	}
};

/*使用方式*/
namespace('Util.EventUtil');

/*Event Code*/
Util.EventUtil.getTarget = function(){};

4、拥有私有成员的单例

在文章(2)中已经提到,私有成员可以用闭包来实现,因为本身作为单例对象,在全局中只有一份实例存在,所以可以不用担心内存的过大消耗。只需通过一个自运行函数就可很容易的实现拥有私有成员的单例:

var Singleton = function(){   
  var privateAttr = 0;   
  
  return {
  	getAttr:function(){
		return privateAttr;
	},
	method:function(){
		alert('11');
	}
  };
}();

5、小结

单例模式是JS中最基本的模式之一。把你的代码包装在一个单例中,就不必担心别人在使用它时会改写到他们自己的全局变量,这是向创建大众使用的API这个方向迈出的一大步,也是成为一个值得信赖的高级JavaScirpt程序员所要经历的第一步。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics