单例模式 (Singleton) 的实如今于保证一个特定类只有一个实例,第二次使用同一个类建立新对象的时候,应该获得与第一次建立对象彻底相同的对象。
当建立一个新对象时,实际上没有其余对象与其相似,由于新对象已是单例了 {a:1} === {a:1} // false
。html
可是如何在对构造函数使用 new 操做符建立多个对象的时候仅获取一个单例对象呢。前端
在构造函数的静态属性中缓存该实例,缺点在于 instance 属性是公开可访问的属性,在外部代码中可能会修改该属性。segmentfault
function Universe() { if (typeof Universe.instance === 'object') { // 判断是否已经有单例了 return Universe.instance } Universe.instance = this return this } var uni1 = new Universe() var uni2 = new Universe() uni1 === uni2 // true
能够把实例封装在闭包中,这样能够保证该实例的私有性而且保证该实例不会在构造函数以外被修改,代价是带来了额外的闭包开销。设计模式
function Universe() { var instance = this Universe = function() { // 重写构造函数 return instance } } var uni1 = new Universe() var uni2 = new Universe() uni1 === uni2 // true
当第一次调用构造函数时,它正常返回 this ,而后在之后调用时,它将会执行重写构造函数,这个构造函数经过闭包访问了私有 instance
变量,而且简单的返回了该 instance
。缓存
有时候对于单例对象须要延迟建立,因此在单例中还存在一种延迟建立的形式,也有人称之为惰性建立
。微信
const LazySingle = (function() { let _instance // 单例的实例引用 function Single() { // 单例构造函数 const desc = '单例' // 私有属性和方法 return { // 暴露出来的对象 publicMethod: function() {console.log(desc)}, publickProperty: '1.0' } } return function() { return _instance || (_instance = Single()) } })() console.log(LazySingle()===lazySingle()) // true console.log(LazySingle().publickProperty) // 1.0
以前在构造函数中重写自身会丢失全部在初始定义和重定义之间添加到其中的属性。在这种状况下,任何添加到 Universe()
的原型中的对象都不会存在指向由原始实现所建立实例的活动连接:闭包
function Universe() { var instance = this Universe = function() { return instance } } Universe.prototype.nothing = true var uni1 = new Universe() Universe.prototype.enthing = true var uni2 = new Universe() console.log(uni1 === uni2) // true uni1.nothing // true uni2.nothing // true uni1.enthing // undefined uni2.enthing // undefined uni1.constructor.name // "Universe" uni1.constructor === Universe // false
之因此 uni1.constructor
再也不与 Universe()
相同,是由于uni1.constructor仍然指向原始的构造函数,而不是重定义以后的那个构造函数。
能够经过一些调整实现原型和构造函数指针按照预期的那样运行:函数
function Universe() { var instance Universe = function Universe() { return instance } Universe.prototype = this // 保留原型属性 instance = new Universe() instance.constructor = Universe // 重置构造函数指针 instance.start_time = 0 // 一些属性 instance.big = 'yeah' return instance } Universe.prototype.nothing = true var uni1 = new Universe() Universe.prototype.enthing = true var uni2 = new Universe() console.log(uni1 === uni2) // true uni1.nothing & uni2.nothing & uni1.enthing & uni2.enthing // true uni1.constructor.name // "Universe" uni1.constructor === Universe // true uni1.big // "yeah" uni2.big // "yeah"
本文是系列文章,能够相互参考印证,共同进步~学习
网上的帖子大多深浅不一,甚至有些先后矛盾,在下的文章都是学习过程当中的总结,若是发现错误,欢迎留言指出~this
参考:
《JavaScript模式》 P143
《Javascript 设计模式》 - 张荣铭
设计模式之单例模式
PS:欢迎你们关注个人公众号【前端下午茶】,一块儿加油吧~
另外能够加入「前端下午茶交流群」微信群,长按识别下面二维码便可加我好友,备注加群,我拉你入群~