js实现单例模式,经常使用两种方法,一种是使用构造函数的静态属性中缓存该实例,另一种是将实例包装在闭包中。
第一种实现方式:
//静态属性中单例模式 function Universe() { if (typeof Universe.instance === "object") { return Universe.instance; } //正常运行 this.start_time = 0; this.bang = "Big"; //缓存 Universe.instance = this; //隐式返回 //return this; } var uni = new Universe(); var uni2 = new Universe(); console.log(uni === uni2 ); //true
第二种实现方式:
/闭包中实现单例模式 function Universe(){ //缓存实例 var instance = this; //正常进行 this.start_time = 0; this.bang = "Big"; //重写该构造函数 Universe = function(){ return instance; } //隐式返回 //return this; } var uni = new Universe(); var uni2 = new Universe(); console.log(uni == uni2); //true
上面实现单例模式有个缺点,就是重写构造函数,会丢失所有在初始化和重定义时刻之间添加到它里面的属性,如下
//test Universe.prototype.nothing = true; var uni = new Universe();
//在创建初始化对象之后,再次向该原型添加属性 Universe.prototype.something = true; var uni2 = new Universe(); console.log(uni.nothing); //true console.log(uni2.nothing); //true console.log(uni2.something); //undefined console.log(uni2.something); //undefined console.log(uni.constructor.name); //Universe console.log(uni.constructor === Universe); //false
其中uni.constructor仍然指向了原始的构造函数。
如果需要使原型和构造函数指针按照预期的那样运行,可以向下面一样改写代码
//如果需要使原型和构造函数指针能够按照预期那样运行,改写如下 function Universe() { //缓存实例 var instance; //重写构造函数 Universe = function Universe() { return instance; }; //保留原型属性 Universe.prototype = this; //实例 instance = new Universe(); //重置构造函数指针 instance.constructor = Universe; //功能实现 instance.start_time = 0; instance.bang = "Big"; return instance; } //test Universe.prototype.nothing = true; var uni = new Universe(); //在创建初始化对象之后,再次向该原型添加属性 Universe.prototype.something = true; var uni2 = new Universe(); console.log(uni.nothing); //true console.log(uni2.nothing); //true console.log(uni2.something); //true console.log(uni2.something); //true console.log(uni.constructor.name); //Universe console.log(uni.constructor === Universe); //true
另一种解决方案是将构造函数和实例包装在即使函数中。
var Universe; (function(){ var instance; Universe = function Universe(){ if(instance){ return instance; } instance = this; //所有的功能 this.start_time = 0; this.bang = "BIg"; } }());