设计模式--单例模式

本文详细介绍了单例模式在前端开发中的应用场景,包括其基本实现方式(ES5和ES6),以及透明版、代理版和惰性单例的改进,强调了其在库引用、弹窗管理、全局状态管理和性能优化等方面的应用。
摘要由CSDN通过智能技术生成

单例模式

创建形的单例模式在前端实际应用中使用场景较多,尤其在于写框架与组件中使用率较高。

介绍/概述:

  • 限制类实例化次数只能一次,确保一个类只有一个实例,并提供一个访问它的全局访问点。

代码演示

实例:简单实现一个全局的 windows 类,保证全局只有一个。

“简单版” 单例模式:

1.ES5 实现
function NewWindow(name) {
    this.name = name;
}
NewWindow.prototype.getName = function () {
    return this.name;
}

//这是构造函数的方法,只能通过构造函数类来访问,而不能通过实例来访问
NewWindow.getInstance = (function () {
    let instance;
    return function (name) {
        if (!instance) {
            instance = new NewWindow(name);
        }
        return NewWindow;
    }
})();

let w1 = NewWindow.getInstance();
let w2 = NewWindow.getInstance();

console.log(w1 === w2) // true 

代码中定义了一个 NewWindow 的全局构造函数(也可类似一个全局变量),然后为其添加一个 getInstance() 方法来控制单例;
getInstance() 方法中采用闭包,存储了一个闭包变量,来达到无论调用多少次 getInstance(),最终都只会返回一个实例对象。
2. ES6类实现

/**
 * 模仿一个全局 window 对象
 */
class NewWindow { 
  // 定义一个静态属性
  private static instance: NewWindow;
  // 实例方法
  public static getInstance() {
    if(!NewWindow.instance) {
      NewWindow.instance = new NewWindow();
    }
    return NewWindow.instance;
  }
}

// 获取 NewWindow 的实例
let w1 = NewWindow.getInstance();
let w2 = NewWindow.getInstance();

console.log(w1 === w2); // true

ES6 与 ES5 实现逻辑类似,都是定义了一个局部私有变量来进行保存,达到最终返回的永远是同一个实例。
以上实现的缺点:
  • 不够“透明”,无法使用 new 来进行类实例化;
  • 使用者必须主动调用 getInstance() 方法,使用麻烦;
  • 功能代码耦合在一起,不符合 “单一职责原则”

“透明版” 单例模式:

主要解决:统一使用 new 操作符来获取单例对象, 而不是 NewWindow.getInstance()

//透明单例
let CreateWindow = (function () {
    let newInstance;
    return function (name) {
        if (newInstance) {
            return newInstance;
        }
        this.name = name;
        return (newInstance = this);
    }
})();

// 首先大家要弄懂 new 一个构造函数,主要做了那几件事
// 结合起来就明白这其中的 newInstance = this
let w1 = new CreateWindow();
let w2 = new CreateWindow();
console.log(w1 === w2); // true

但是现在虽然是可以用 new 创建了,但是还有个小问题,就是不够灵活,其中的 this.name = name 没有与对象创建操作进行拆分,不符合“单一职责原则”。

“代理版“ 单例模式:

主要解决:将管理单例操作,与对象创建操作进行拆分,实现更小的粒度划分,符合“单一职责原则”

// 单独一个 NewWindow 类,处理实例对象,做到分离
function NewWindow(name) {
    this.name = name;
}
NewWindow.prototype.getName = function () {
    console.log(this.name);
}

// CreateWindow 只需要管理单例的操作创建
let CreateWindow = (function () {
    let instance;
    return function (name) {
        if (!instance) {
            instance = new NewWindow(name);
        }
        return instance;
    }
})();

let w1 = new CreateWindow('window1');
let w2 = new CreateWindow('window2');
console.log(w1 === w2);
console.log(w1.getName());  // 'window1'
console.log(w2.getName());  // 'window1'

“惰性单例” 模式

主要解决:需要时才创建类实例对象。对于懒加载的性能优化,想必前端开发者并不陌生。惰性单例也是解决 “按需加载” 的问题。

实例:页面弹窗提示,多次调用,都只有一个弹窗对象,只是展示信息内容不同。
  • 开发这样一个全局弹窗对象,我们可以应用单例模式。为了提升它的性能,我们可以让它在我们需要调用时再去生成实例,创建 DOM 节点。
let getSingleton = function(fn) {
    var result;
    return function() {
        return result || (result = fn.apply(this, arguments)); // 确定this上下文并传递参数
    }
}
let createAlertMessage = function(html) {
    var div = document.createElement('div');
    div.innerHTML = html;
    div.style.display = 'none';
    document.body.appendChild(div);
    return div;
}

let createSingleAlertMessage = getSingleton(createAlertMessage);
document.body.addEventListener('click', function(){
    // 多次点击只会产生一个弹窗
    let alertMessage = createSingleAlertMessage('您的知识需要付费充值!');
    alertMessage.style.display = 'block';
})

单例模式的应用场景

1.引用第三方库(多次引用只会使用一个库引用,如 jQuery)

if(window.jQuery!=null){
  return window.jQuery;
}else{
    //init~~~~~~~
}

2. 弹窗(登录框,信息提升框)

3. 淘宝购物车 (一个用户只有一个购物车)

4. 全局态管理 store (Vuex / Redux)

//redux 整个应用只有一个仓库,整个仓库只有一个状态state
function createStore(reducer) {
    let state;
    let listeners = [];
    function subscribe(listener) {
        listeners.push(listener);
    }
    function getState() {
        return state;
    }
    function dispatch(action) {
        state = reducer(state, action);
    }
    return {
        getState,
        dispatch,
        subscribe
    }
}

let reducer = function () {}
let store = createStore(reducer);

参考地址:

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值