Javascript设计模式之单例模式

220 阅读2分钟

前言:菜鸡也有梦想,而我的梦想就是进一个真正的互联网大厂。以前学习的时候没有系统的整理,从今天开始要保持每周写博客的习惯,希望自己可以有所成长。为了培养编程思维,决定从设计模式开始写起。我是通过读《Javascript设计模式与开发实践》来学习设计模式,并且将知识点和收获记录在博客中。

此文仅记录本人阅读《JavaScript设计模式与开发实践》的知识点与想法,感谢作者曾探大大写出这么好的一本书。如有冒犯,请联系本人:markcoder@outlook.com处理,请大家购买正版书籍。

1. 单例模式介绍

单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

比如登录框和购物车就适合用单例模式。

2.代码实现

要点:用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象。

const 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;
};

let a = Singleton.getInstance('event1');
let b = Singleton.getInstance('event2');

console.log(a === b); // true

或者

const Singleton = function (name) {
    this.name = name;
};

Singleton.prototype.getName = function () {
    alert(this.name);
};

Singleton.getInstance = (function () {
    let instance = null;
    return function (name) {
        if (!instance) { // 如果之前没有创建过实例
            instance = new Singleton(name);
        }
        return instance;
    }
})();

let a = Singleton.getInstance('event1');
let b = Singleton.getInstance('event2');

console.log(a === b); // true

ES6实现

class Singleton {
    login () {
        console.log(login)
    }
}

Singleton.getInstance = (function () {
    let instance;
    return function () {
        if (!instance) {
            instance = new Singleton();
        }
        return instance;
    }
})();

let a = Singleton.getInstance();
let b = Singleton.getInstance();

console.log(a === b); // true

Singleton类的使用者必须知道通过 Singleton.getInstance 这个方法来获取对象,而不是通过 new XXX 的方式。

3.透明的单例模式

let CreateDiv = (function () {
    
    let instance;
    
    let CreateDiv = function (html) {
        if (instance) {
            return instance;
        }
        this.html = html;
        this.init();
        return instance = this;
    };
    
    CreateDiv.prototype.init = function () {
        let div = document.createElement('div');
        div.innerHTML = this.html;
        document.body.appendChild(div);
    };
    
    return CreateDiv; // 返回真正的构造方法
    
})();

let a = new CreateDiv( 'event1' ); 
let b = new CreateDiv( 'event2' ); 

console.log ( a === b ); // true 

通过匿名函数返回真正的构造函数 CreateDiv 。假如某天我们要在页面中创建更多的div,就需要修改构造函数,所以代码仍然需要改进。

4.用代理实现单例模式

let CreateDiv = function (html) {
    this.html = html;
    this.init();
};
    
CreateDiv.prototype.init = function () {
    let div = document.createElement('div');
    div.innerHTML = this.html;
    document.body.appendChild(div);
};

// 利用闭包将管理单例模式的逻辑放在了proxySingleton
let proxySingleton = (function () {
    var instance;
    return function (html) {
        if (!instance) {
            instance = new CreateDiv(html);
        }
        return instance;
    }
})();

let a = new proxySingleton( 'sven1' ); 
let b = new proxySingleton( 'sven2' ); 
console.log ( a === b ); 

5.使用单例模式的总结

  • 模拟登录框
class Login {
    constructor () {
        this.state = 'hide'
    }
    
    show () {
        if (this.state === 'show') {
            return    
        }    
        this.state = 'show'
    }
    
    hide () {
        if (this.state === 'hide') {
            return
        }
        this.state = 'hide'
    }
}

Login.getInstance = (function () {
    let instance;
    return function () {
         if (!instance) {
            instance = new Login();
        }
        return instance   
    }
})();

let login1 = Login.getInstance();
let login2 = Login.getInstance();

console.log(login1 === login2);
  • 无论引入多少次jQuery库,全局只有一个$
if (window.jQuery != null) {
    return window.jQuery
} else {
    // 初始化
}
  • vuex和redux的store

参考

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