JS单例模式《JavaScript设计模式与开发实践》阅读笔记

此文仅记录本人阅读《JavaScript设计模式与开发实践》这个本时的感觉,感谢做者曾探写出这么好的一本书。若有冒犯,若有错误,请联系本人:luogao_lg@sina.com处理。javascript

这一章让我知道了单例模式的核心就是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。但在JavaScript中单例模式有别的区别于传统面向对象语言的应用,惰性单例模式在实际的开发中有不少用途,例如提升页面性能,避免没必要要的DOM操做等。html

为什么要有单例模式

书中有举出一个实际场景,当咱们点击登录按钮时,页面中可能会出现一个弹框,而这个弹框是惟一的,不管点多少次登录按钮,弹框只会被建立一次,那么这种状况下就适合用单例模式来建立弹框。java

实现一个简单的单例模式

如下代码来自书中编程

var CreateDiv = (function(html) {
    var instance
    var CreateDiv = function() {
        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.appendChild(div)
    }
    return CreateDiv
})()
复制代码

以上代码经过自执行函数和闭包将instance封装起来。而且返回了真正的Singleton构造方法。设计模式

经过观察上面代码发现CreateDiv里执行了两个操做:闭包

  • 1.建立对象而且执行init方法。
  • 2.保证只有一个对象。这里就暴露出一个问题。

若是某天咱们须要用这个方法向页面中建立更多的元素。那咱们必需要改写CreateDiv,若是咱们结合“单一职责原则”,咱们就知道要去把保证只有一个对象这个操做从CreateDiv抽离出来。这个目的能够经过代理来实现。app

用代理实现单例模式

首先咱们把上面代码中的CreateDiv方法改写成一个只负责建立DIV的类函数

var CreateDiv = function(html) {
    this.html = html
    this.init()
}

CreateDiv.prototype.init = function() {
    var div = document.createElement('div')
    div.innerHTML = this.html
    document.appendChild(div)
}
复制代码

接下来引入代理类性能

var ProxysingletonCreateDiv = (function() {
    var instance
    return function(html) {
        if (!instance) {
            instance = new CreateDiv(html)
        }
        return instance
    }
})()
var a = new ProxysingletonCreateDiv('test1')
var b = new ProxysingletonCreateDiv('test2')

alert(a === b) // true
复制代码

至此利用代理类也实现了一个单例模式。但目前咱们讨论的单例模式跟接近传统面向对象语言中的实现。接下来咱们来了解一下JavaScript中的单例模式。网站

JavaScript中的单例模式——惰性单例

了解了单例模式的一些实现方法以后。咱们能够来看看惰性单例的实现,这种实现方式在JavaScript的实际编程中是很实用的。

惰性单例

惰性单例是指在须要的时候才建立对象实例,而不是像以前的代码那样,利用自执行函数在代码执行时就把对象实例建立。

好比最开始就提到,当打开一个网站时,须要登陆,但登录的弹窗只会在点击登录按钮时出现,甚至有的网站不须要登陆就能直接浏览。这时咱们并不须要在页面加载时就去建立一个弹窗。咱们大可在须要用的时候去建立。

<html>
    <body>
        <button id="loginBtn">登陆</button>
    </body>
    <script> var createLoginLayer = (function() { var div return function() { if (!div) { var div = document.createElement('div') div.innerHTML = '我是登陆弹窗' div.style.display = 'none' document.appendChild(div) } return div } })() document.getElementById('loginBtn').onclick = function() { var loginLayer = createLoginLayer() loginLayer.style.display = 'block' } </script>
</html>
复制代码

以上咱们实现了一个单例模式的弹窗。可是咱们仍是能够把其中的控制只有一个对象的操做抽离出来,让咱们来实现一个通用的惰性单例。

通用惰性单例

通用惰性单例的实现就是要抽离全部单例模式都要实现的——控制只有一个对象。那么咱们来看看控制只有一个对象的操做抽象出来是个什么样子:

var obj 
if (!obj) {
    obj = xxx
}
复制代码

因而就能够把这个操做的逻辑封装到一个getSingle函数中,而后把要执行的函数看成参数传入进去:

var getSingle = function(fn) {
    var result
    return function() {
        result || (result = fn.apply(this, arguments))
    }
}
复制代码

这样咱们上面写的建立弹窗的方法就能够彻底抽离出来:

var createLoginLayer = function() {
    var div = document.createElement('div')
    div.innerHTML = '我是登陆弹窗'
    div.style.display = 'none'
    document.appendChild(div)
    return div
}

var createSingleLoginLayer = getsingle(createLoginLayer)

document.getElementById('loginBtn').onclick = function() {
    var loginLayer = createSingleLoginLayer()
    loginLayer.style.display = 'block'
}
复制代码

至此咱们实现了一个getSingle函数来帮咱们实现只有一个实例对象的目的,而且将实例对象要作的指责独立出来,两个方法互不打扰。

最后

原文出自 Roy's Blog

参考

《JavaScript设计模式与开发实践》—— 曾探

相关文章
相关标签/搜索