单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏览器中的 window 对象等。
JavaScript 中的单例模式
1. 使用命名空间
在JavaScript里,实现单例的方式有很多种,其中最简单的一个方式是使用对象字面量的方法,其字面量里可以包含大量的属性和方法:
let people = {
name: "Jack",
age: 18,
play() {
console.log('i like game');
}
}
还可以动态地创建命名空间
// 定义对象
var MyApp = {};
// 对象的方法
MyApp.namespace = function( name ){
// 将参数分割成数组
var parts = name.split( '.' );
// 定义变量
var current = MyApp;
// 创建对象里面的属性
for ( var i in parts ){
if ( !current[ parts[ i ] ] ){
current[ parts[ i ] ] = {};
}
current = current[ parts[ i ] ];
}
};
MyApp.namespace( 'event' );
MyApp.namespace( 'dom.style' );
/******************* 上面没看懂没关系 ***********************/
// 上述代码等价于
var MyApp = {
event: {},
dom: {
style: {}
}
};
2. 使用闭包封装私有变量
var user = (function(){
var __name = 'sven',
__age = 29;
return {
getUserInfo: function(){
return __name + '-' + __age;
}
}
})();
我们用下划线来约定私有变量 __name
和 __age
,它们被封装在闭包产生的作用域中,外部是访问不到这两个变量的,这就避免了对全局的命令污染。
实现一个标准的单例模式
var Singleton = function( name ){
this.name = name;
this.instance = null;
};
Singleton.prototype.getName = function(){
alert ( this.name );
};
Singleton.getInstance = function( name ){
if ( !this.instance ){
this.instance = new Singleton( name );
}
return this.instance;
};
var a = Singleton.getInstance( 'sven1' );
var b = Singleton.getInstance( 'sven2' );
alert ( a === b ); // true
我们通过 Singleton.getInstance
来获取 Singleton
类的唯一对象,这种方式相对简单,但有一个问题,就是增加了这个类的“不透明性”, Singleton
类的使用者必须知道这是一个单例类,跟以往通过 new XXX
的方式来获取对象不同,这里偏要使用 Singleton.getInstance
来获取对象。
透明的单例模式
var CreateDiv = (function(){
var instance;
var CreateDiv = function( html ){
if ( instance ){
return instance;
}
this.html = html;
this.init();
return instance = this;
};
CreateDiv.prototype.init = function(){
var div = document.createElement( 'div' );
div.innerHTML = this.html;
document.body.appendChild( div );
};
return CreateDiv;
})();
var a = new CreateDiv( 'sven1' );
var b = new CreateDiv( 'sven2' );
alert ( a === b ); // true
为了把 instance
封装起来,我们使用了自执行的匿名函数和闭包,并且让这个匿名函数返回
真正的 Singleton
构造方法,这增加了一些程序的复杂度
3. 用代理实现单例模式
var CreateDiv = function( html ){
this.html = html;
this.init();
};
CreateDiv.prototype.init = function(){
var div = document.createElement( 'div' );
div.innerHTML = this.html;
document.body.appendChild( div );
};
// 代理类 proxySingletonCreateDiv:
var ProxySingletonCreateDiv = (function(){
var instance;
return function( html ){
if ( !instance ){
instance = new CreateDiv( html );
}
return instance;
}
})();
var a = new ProxySingletonCreateDiv( 'sven1' );
var b = new ProxySingletonCreateDiv( 'sven2' );
alert ( a === b );
通过引入代理类的方式,我们同样完成了一个单例模式的编写,跟之前不同的是,现在我们
把负责管理单例的逻辑移到了代理类 proxySingletonCreateDiv
中。这样一来,CreateDiv
就变成了一个普通的类,它跟 proxySingletonCreateDiv
组合起来可以达到单例模式的效果。
惰性单例
惰性单例指的是在需要的时候才创建对象实例。
var Singleton = (function () {
var instantiated;
function init() {
/*这里定义单例代码*/
return {
publicMethod: function () {
console.log('hello world');
},
publicProperty: 'test'
};
}
return {
getInstance: function () {
if (!instantiated) {
instantiated = init();
}
return instantiated;
}
};
})();
/*调用公有的方法来获取实例:*/
Singleton.getInstance().publicMethod();
通过以上方法我们就可以做到只有在使用的时候才初始化,从而达到节约资源的目的
目前对于单例模式的理解就这么多,以后有了新的理解会继续更新的,溜了溜了(~ ̄▽ ̄)~