前言

本篇主要是读 《JavaScript 设计模式核⼼原理与应⽤实践》的笔记记录。

《JavaScript 设计模式核⼼原理与应⽤实践》的思维导图:

image

开放封闭原则

软件实体(类、模块、函数)可以扩展,但是不可修改。

JS设计模式

工厂模式·简单工厂

工厂模式其实就是将创建对象的过程单独封装

例如,软件注册中,让用户选择自己的职业后,新增一个用户

function User(name, email, password, remarks){
    this.name = null
    this.email = null 
    this.password = null
    // 备注
    this.remarks = null
}

function FactoryGetUser(name, email, password, career) {
    let remarks
    switch(career) {
        case 'coder':
            remarks =  ['技术'] 
            break
        case 'product':
            remarks = ['产品']
            break
        case 'xxx':
            // 其它工种的备注
            ...
            
    return new User(name, age, password, remarks)
}

// 调用
let baseUser = FactoryGetUser(null, null, null, "coder")

工厂模式·抽象工厂

这个模式在后端是非常常见的。

在后端其实就是abstract class,只是es6 js没有这种写法,但是可以曲线救国实现。

例如团队项目内有Axios请求又有ajax请求的(不会真有这样的项目吧...),我们可以将请求封装一下:

// 模拟抽象类
class requestFactory {
    // 请求的方法
    request(){
        throw new Error("抽象工厂方法不允许直接调用,你需要将我重写!");
    }
}


// 将Axios请求继承抽象类
class AxiosFactory extends requestFactory {
    // 请求的方法
    request(url="", method="get", data=null){
        // axios(...) balabalabala...
        return res;
    }
}

// 将ajax请求继承抽象类
class AjaxFactory extends requestFactory {
    // 请求的方法
    request(url="", method="get", data=null){
        // $.ajax balabalabala...
        return res;
    }
}


/**
 * 使用
 */
 
// 用Axios去请求
let rq = new AxiosFactory();
rq.request("http://xxxx", "post", {});

// 用Ajax去请求
let rq = new AjaxFactory();
rq.request("http://xxxx", "post", {});

这个例子最大的作用大概就是统一了团队内请求调用风格了。

总结:抽象工厂不干活,具体工厂来干活!

单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点,这样的模式就叫做单例模式。

众所周知每次new出来的对象都是独立的,但在一些业务场景中我们希望无论在何处new都是最先那个。

比如当前登录用户:

class NowUser {
    getUserInfo() {
        return {
            token: this.token,
            name: this.name,
            email: this.email,
            remarks: this.remarks,
        }
    }
    static getInstance() {
        // 判断是否已经new过1个实例
        if (!NowUser.instance) {
            // 若这个唯一的实例不存在,那么先创建它
            NowUser.instance = new NowUser()
        }
        // 如果这个唯一的实例已经存在,则直接返回
        return NowUser.instance
    }
}

// 在其它地方中获取当前用户信息
const user1 = NowUser.getInstance()
user1.name="张三"
const user2 = NowUser.getInstance()

user1 === user2 // true

原型模式

原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。

适用于大对象的创建,因为创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需内存拷贝即可。

js深拷贝

function deepClone(obj) {
    // 如果是 值类型 或 null,则直接return
    if(typeof obj !== 'object' || obj === null) {
        return obj
    }
    
    // 定义结果对象
    let copy = {}
    
    // 如果对象是数组,则定义结果数组
    if(obj.constructor === Array) {
        copy = []
    }
    
    // 遍历对象的key
    for(let key in obj) {
        // 如果key是对象的自有属性
        if(obj.hasOwnProperty(key)) {
            // 递归调用深拷贝方法
            copy[key] = deepClone(obj[key])
        }
    }
    
    return copy
}