定义
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
优缺点
优点:避免频繁创建和销毁实例,减少内存占用等。 缺点:不适用动态扩展对象,或需创建多个相似对象的场景。
用途
- 引用第三方库(多次引用只会使用一个库引用,如 jQuery)
- 全局通用弹窗(如登录弹窗)
- 全局状态管理(Vuex、Redux)等场景
基础例子
class Test {
constructor() {
if (Test.instance) {
return Test.instance;
}
Test.instance = this;
}
}
const t1 = new Test();
const t2 = new Test();
console.log('t1===t2', t1 === t2);
只有没有 Test.instance 才会走类的初始化,有 Test.instance 则直接返回已经初始化过的实例,从而保证实例是唯一的。
全局登录弹窗例子
import React from 'react';
const openLoginModal = (function () {
let div;
return function () {
if (!div) {
div = document.createElement('div');
div.innerHTML = '登录弹窗';
document.body.appendChild(div);
}
return div;
};
})();
const Index = () => {
return (
<span
onClick={() => {
openLoginModal();
}}
>
打开弹窗
</span>
);
};
export default Index;
上面的登录弹窗例子还存在一些代码设计上的问题:openLoginModal 既实现了单例的逻辑,也实现了创建登录弹窗的逻辑。这违反了单一职责原则,如果下次仍然需要创建另一个弹窗,我们无法复用创建弹窗的逻辑。所以我们需要将不变的部分抽离出来,编写一个通用单例创建的代理方法。
import React from 'react';
// 通用单例创建代理方法
const getSingle = function (fn) {
let result;
return function () {
return result || (result = fn.apply(this, arguments));
};
};
const openLoginModal = function () {
const div = document.createElement('div');
div.innerHTML = '登录弹窗';
document.body.appendChild(div);
return div;
};
const singleOpenLoginModal = getSingle(openLoginModal);
const Index = () => {
return (
<span
onClick={() => {
singleOpenLoginModal();
}}
>
打开弹窗
</span>
);
};
export default Index;