单例模式的定义是:保证一个类仅有一个实例,并提供访问它的全局访问点
实现单例模式
要实现一个标准的单例模式并不复杂,无非是一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象。
var Singleton = function (name) {this.name = namethis.instance = null}Singleton.prototype.getName = function () {console.log(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('sven1')console.log(a === b) // true
or
var Singleton = function (name) {this.name = name}Singleton.prototype.getName = function () {console.log(this.name)}Singleton.getInstance = (function () {var instance = nullreturn function (name) {if (!instance) {instance = new Singleton(name)}return instance}})()
透明的单例模式
我们现在的目标是实现一个“透明”的单例类,用户从这个类中创建对象的时候,可以像使 用其他任何普通类一样。在下面的例子中,我们将使用 CreateDiv 单例类,它的作用是负责在页 面中创建唯一的 div 节点,代码如下:
var CreateDiv = (function () {var instancevar CreateDiv = function (html) {if (instance) {return instance}this.html = htmlthis.init()return (instance = this)}CreateDiv.prototype.init = function () {var div = document.createElement('div')div.innerHTML = this.htmldocument.body.appendChild(div)}return CreateDiv})()var a = new CreateDiv('sven1')var b = new CreateDiv('sven2')console.log(a === b)
用代理实现单例模式
var CreateDiv = function (html) {this.html = htmlthis.init()}CreateDiv.prototype.init = function () {var div = document.createElement('div')div.innerHTML = this.htmldocument.body.appendChild(div)}// 接下来引入代理类ProxySingletonCreateDivvar ProxySingletonCreateDiv = (function () {var instancereturn function (html) {if (!instance) {instance = new CreateDiv(html)}return instance}})()var a = new ProxySingletonCreteDiv('sven1')var b = new ProxySingletonCreteDiv('sven1')console.log(a === b)
通过引入代理类的方式,我们同样完成了一个单例模式的编写,跟之前不同的是,现在我们 把负责管理单例的逻辑移到了代理类 proxySingletonCreateDiv 中。这样一来,CreateDiv 就变成了 一个普通的类,它跟 proxySingletonCreateDiv 组合起来可以达到单例模式的效果。
JavaScript中的单利模式
全局变量不是单例模式,但在 JavaScript 开发中,我们经常会把全局变量当成单例来使用。
使用命名中间
把 a 和 b 都定义为 namespace1 的属性,这样可以减少变量和全局作用域打交道的机会
var namespace1 = {a: function () {console.log(1)},b: function () {console.log(2)},}
我们还可以动态地创建命名空间 ```javascript 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’)
console.dir(MyApp)
// 上诉代码等价于
var MyApp = { event: {}, dom: { style: {}, }, }
<a name="QJRjq"></a>#### 使用闭包封装私有变量```javascriptvar user = (function () {var __name = 'sven'var __age = 29return {getUserInfo: function () {return __name + '-' + __age},}})()
惰性单例模式
惰性单例指的是在需要的时候才会创建对象实例
Singleton.getInstance = (function () {var instance = nullreturn function (name) {if (!instance) {instance = new Singleton(name)}return instance}})()
登录浮窗的单例实现
我们登录网页qq的时候,需要登录,此时的登录应当只有一个
- 当我们点击的时候,才会弹出来(不点击的时候,压根就不创建)
```javascript
var createLoginLayer = (function () {
var div
return function () {
if (!div) {
} return div } })()div = document.createElement('div')div.innerHTML = '我是登录浮窗'div.style.display = 'none'document.body.appendChild(div)
document.getElementById(‘loginBtn’).onclick = function () { var loginLayer = createLoginLayer() loginLayer.style.display = ‘block’ }
<a name="j6RoB"></a>#### 通用的惰性单例```javascriptvar getSingle = function (fn) {var resultreturn function () {return result || (result = fn.apply(this.arguments))}}
var createLoginLayer = function () {var div = document.createElement('div')div.innerHTML = '我是登录浮窗'div.style.display = 'none'document.body.appendChild(div)return div}var createSingleLoginLayer = getSingle(createLoginLayer)document.getElementById('loginBtn').onclick = function () {var loginLayer = createSingleLoginLayer()loginLayer.style.display = 'block'}
