JavaScript设计模式

1. 定义 保证一个类仅有一个实例,并提供一个访问它的全局访问点
2. 核心 确保只有一个实例,并提供全局访问
3. 实现 假设要设置一个管理员,多次调用也仅设置一次,我们可以使用闭包缓存一个内部变量来实现这个单例

function SetManager(name) {
    this.manager = name;
}
SetManager.prototype.getName = function() {
    console.log(this.manager);
};
var SingletonSetManager = (function() {
    var manager = null;
    return function(name) {
        if (!manager) {
            manager = new SetManager(name);
        }
        return manager;
    }
})();
SingletonSetManager('a').getName(); // a
SingletonSetManager('b').getName(); // a
SingletonSetManager('c').getName(); // a

这是比较简单的做法,但是假如我们还要设置一个HR呢?就得复制一遍代码了
所以,可以改写单例内部,实现地更通用一些

// 提取出通用的单例
function getSingleton(fn) {
    var instance = null;
    return function() {
        if (!instance) {
            instance = fn.apply(this, arguments);
        }
        return instance;
    }
}

再进行调用,结果还是一样

// 获取单例
var managerSingleton = getSingleton(function(name) {
    return new SetManager(name);
});
managerSingleton('a').getName(); // a
managerSingleton('b').getName(); // a
managerSingleton('c').getName(); // a

这时,我们添加HR时,就不需要更改获取单例内部的实现了,仅需要实现添加HR所需要做的,再调用即可

function SetHr(name) {
    this.hr = name;
}
SetHr.prototype.getName = function() {
    console.log(this.hr);
};
var hrSingleton = getSingleton(function(name) {
    return new SetHr(name);
});
hrSingleton('aa').getName(); // aa
hrSingleton('bb').getName(); // aa
hrSingleton('cc').getName(); // aa

或者,仅想要创建一个div层,不需要将对象实例化,直接调用函数
结果为页面中仅有第一个创建的div

function createPopup(html) {
    var div = document.createElement('div');
    div.innerHTML = html;
    document.body.append(div);

    return div;
}

var popupSingleton = getSingleton(function() {
    var div = createPopup.apply(this, arguments);
    return div;
});

console.log(
    popupSingleton('aaa').innerHTML,
    popupSingleton('bbb').innerHTML,
    popupSingleton('bbb').innerHTML
); // aaa  aaa  aaa